Error when trying to authenticate users with google in firebase - flutter

I've been struggling with this for months, sinc.e I'm just learning firebase with flutter.
I have a simple button that when pressed should give the option to register or start section with google, but when running I get errors in the console.
There are so many that I don't know which one it is.
Error: Assertion failed:
file:///C:/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-1.7.2/lib/src/firebase_core_web.dart:207:11
options != null
"FirebaseOptions cannot be null when creating the default app."
Error: [core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()
here in onpress of the button:
child: MaterialButton(
onPressed: () async {
User? user = await Authenticator.IniciarSesion(context: context);
print(user?.displayName);
},
and the class that authenticates
class Authenticator {
static Future<User?> IniciarSesion({required BuildContext context}) async {
FirebaseAuth authenticator = FirebaseAuth.instance;
User? user;
GoogleSignIn objGooglesignIn = GoogleSignIn();
GoogleSignInAccount? objGooglesignInAccount =
await objGooglesignIn.signIn();
if (objGooglesignInAccount != null) {
GoogleSignInAuthentication objGoogleSignInAuthentication =
await objGooglesignInAccount.authentication;
AuthCredential credential = GoogleAuthProvider.credential(
accessToken: objGoogleSignInAuthentication.accessToken,
idToken: objGoogleSignInAuthentication.idToken);
try {
UserCredential userCredential =
await authenticator.signInWithCredential(credential);
user = userCredential.user;
return user;
} on FirebaseAuthException catch (e) {
print("error de auth");
}
}
}
}
Sorry if I put a lot of code. I don't know exactly what the error could be.

There are two issues with your application, first one seems like you are not initializing firebase in the main function properly. Please refer mentioned link for setup.
Flutter firebase setup guide
Additionally as I can see there is no firebase_options.dart in your lib directory which basically manages (api key) configurations for different platforms.
If you have followed steps mentioned in guide correctly you can create these configs using
flutterfire configure
command only after you have already installed flutterfire cli using following command
dart pub global activate flutterfire_cli

Related

Flutter Google Sign In Keeps Asking for Permission

I am working with the Google Sign In auth through Firebase but each time I test the app in iOS Google keeps asking for permissions whenever I login with Google Sing In. In Android it only asks for permission once.
Has anyone encountered a similar issue?
This is my Google Sign In code:
class AuthService {
signInWithGoogle() async {
final GoogleSignInAccount? gUser = await GoogleSignIn().signIn();
final GoogleSignInAuthentication gAuth = await gUser!.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: gAuth.accessToken,
idToken: gAuth.idToken,
);
await FirebaseAuth.instance.signInWithCredential(credential);
}
}
I tried to find another code but none of them worked!
Please make sure that you have enabled Google authentication in firebase and is using the updated google-services.json file and GoogleService-Info.plist files.
You can make use of google_sign_in package.
Also, please add the scope when instantiating Google signin
GoogleSignIn googleSignIn = GoogleSignIn(
scopes: [
'email',
],
);
GoogleSignInAccount? gAccount = await googleSignIn.signIn();
final credential = await gAccount!.authentication;

creating user is changing the current user

I have following code to login in firebase using flutter. This works fine.
FirebaseAuth.instance.signInWithEmailAndPassword(email: myemail, password: mypassword);
After successful authentication, I am creating nw user using below code.
UserCredential userCredentials = await FirebaseAuth.instance.createUserWithEmailAndPassword(email: myemail, password: mypassword);
but, with approach, the current user changes. I want to create the user without changing the current User. Is this possible?
I have found one solution and it's working for me
In main dart file initializeApp like this
void main() async{
await Firebase.initializeApp();
runApp(MyApp());
}
Create a simple/admin user
FirebaseAuth.instance.signInWithEmailAndPassword(email: myemail, password: mypassword);
Add another user
FirebaseApp app = await Firebase.initializeApp(
name: 'secondary', options: Firebase.app().options);
await FirebaseAuth.instanceFor(app: app)
.createUserWithEmailAndPassword(
email: _email, password: _password);
app.delete();
This is a duplicate of Flutter: Firebase Authentication Create User Without Automatically Logging In, but I can't flag the question as it has an open bounty.
You need to create a second instance of FirebaseApp and create the new user with that instance:
static Future<UserCredential> register(String email, String password) async {
FirebaseApp app = await Firebase.initializeApp(
name: 'Secondary', options: Firebase.app().options);
try {
UserCredential userCredential = await FirebaseAuth.instanceFor(app: app)
.createUserWithEmailAndPassword(email: email, password: password);
}
on FirebaseAuthException catch (e) {
// Do something with exception. This try/catch is here to make sure
// that even if the user creation fails, app.delete() runs, if is not,
// next time Firebase.initializeApp() will fail as the previous one was
// not deleted.
}
await app.delete();
return Future.sync(() => userCredential);
}
What you are trying to do is not secure (generating someone else's password)
And you are correct in that sense there is no way to create a password for another email, as an admin.
What you want to do is sendSignInLinkTOEmail.
This is just the same procedure to sign up with GSuit and other popular services as well.
In case if you really need to set up users, you have to use a separate auth module (should be easy to write your own) and not firebase, and then link the users together when they sign up. It's a hacky way and I don't recommend it.

Flutter Google Sign In idToken expired

I am using google_sign_in for auth in my flutter application.
I followed steps documented here to get started:
https://github.com/flutter/plugins/blob/master/packages/google_sign_in/google_sign_in/example/lib/main.dart
I get idToken as recommended to perform auth on the server side.
This is the code snippet I use to get idToken
_googleSignIn.onCurrentUserChanged.listen(
(GoogleSignInAccount account) {
setState(() {
developer.log("************Changing account");
_currentUser = account;
account.authentication.then((key){
developer.log("########### Changing token");
_userToken=key.idToken;
});
});
});
When I send idToken (_userToken in above example) it works fine for sometime, and later I see the following error message on the server side:
Token expired, 1593370077 < 1593384191
IT looks like token has an expiration time and expires after a while.
I tried moving above code snippet from initState() to build(). Here my assumption if I call it everytime when I am building the widget I should get a new token. THAT DIDN'T WORK
Reason I thought it might work was because when I "Run .dart" (not hot reload) it works. This made me assume moving it to build might work . It didn't work
My question: What is the programmatic way to refresh token, or get a new token in flutter using google_sign_in.
Thanks for your help!!
The idToken expires every 30 minutes.
To refresh the token you can either user the API or do a silent login like this:
Future<String> refreshToken() async {
final GoogleSignInAccount googleSignInAccount =
await googleSignIn.signInSilently();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
await auth.signInWithCredential(credential);
return googleSignInAuthentication.accessToken; //new token
}

How can you log into google oauth with a preset email and password?

I'm working on a flutter app for a client.
This involves uploading files to a Google drive folder.
I've got it working with the Google sign in pop-up, but they want it so that the account used is separated from the device accounts.
Is this possible?
I don't think service accounts are right because they still want the email and password to be set in the app settings, and from what I understand service accounts need to be made and linked directly in the API console.
EDIT: here's my current code for logging in with the Google sign-in plugin;
static final GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [
g.DriveApi.DriveScope,
g.DriveApi.DriveMetadataReadonlyScope
]
);
static dynamic token;
...
static login() async{
try {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser
.authentication;
print("signed in " + googleAuth.accessToken);
token = googleAuth.accessToken;
_authHeaders = await _googleSignIn.currentUser.authHeaders;
}catch(exception){
//maybe offline
print("login error: "+exception.toString());
}
}
So is it possible to use email and password instead of this method (which show's an account selection pop-up)?

How to determine which provider the user logged in with

I am using multiple Firebase sign in methods in my app (Facebook, Google, Phone, etc). But once the user is logged in, I am unable to determine which provider was used to sign in.
I tried below(very close to the recommended solution. But does not work):
_auth.currentUser().providerData[0].providerId
I expect it to return something like "google.com" or "facebook.com"
Instead it returns "firebase"
I cant find any other solution where it clearly lets us determine if a google or facebook sign in was used. All solutions in the forum iOS specific or for web. Can't find anything flutter specific. Appreciate any help in advance.
I checked and _auth.currentUser().providerData[0].providerId does provide "google.com" or "facebook.com"
Not sure at what point it showed me "firebase". Will post to this if I figure this out
You can use the following code :
#override
Future<void> signOut() async {
final FirebaseAuth _auth = FirebaseAuth.instance;
try {
final _providerData = _auth.currentUser!.providerData;
if (_providerData.isNotEmpty) {
if (_providerData[0]
.providerId
.toLowerCase()
.contains('google')) {
await GoogleSignIn().signOut(); // google signOut
} else if (_providerData[0]
.providerId
.toLowerCase()
.contains('facebook')) {
await FacebookAuth.instance.login(); // facebook signOut
}
}
await _auth.signOut(); // firebase signOut
} catch (e) {
print(e);
}
}
I am not sure about facebook since I have never implemented login with facebook, but for Google, you may be able to do something like this.
You probably have a statement similar to GoogleSignInAccount googleUser = await _googleSignIn.signIn(). Why not check if google User is null or not once the user is signed in or on auth change? This will let you know if the user signed in with google.
Similar functionality for facebook should be possible but I just don't know if it is the same.
If googleUser != null then google was used.
If say facebookUser != null then facebook was used,
Then if googleUser is null and say facebookUser is null it was email.
Maybe this is helpful, maybe not, but it is just what I could think of right now.