I'm using Firebase and when I use await GoogleSignIn.signIn() a modal shadow shows on top of my app blocking user interaction until if finishes its business.
If it's the first time and the user need to fill or pick a credential (email account) that's understandable.
But once the user has registered it's very annoying to open the app and have to wait for it to finish before interacting with the app. My code is all async and nothing from my part is blocking the user interaction.
Everything works well in the background when using other login methods like passwordless login. But when I use GoogleSignIn, it just throws this modal shadow on top of my app and blocks user interaction.
Am I doing something wrong? Maybe I shouldn't be calling GoogleSignIn.signIn() every time the app is opened after the user has already registered? Or is it just as it's supposed to be?
It takes about a second to finish his business but it's enough to annoy and it can take longer depending on the network connectivity. And if the connection fails, it takes about 5 seconds to give up and throw the error.
The way my app is designed there's no reason to hold the user until he has logged in. He can even use my app offline so I'd really like to change this behavior.
EDIT
Here's my sign in code:
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
user = (await FirebaseAuth.instance.signInWithCredential(credential)).user;
check for user, if user is not present then signIn
if (FirebaseAuth.instance.currentUser == null) {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
user = (await FirebaseAuth.instance.signInWithCredential(credential)).user;
} else {
user = FirebaseAuth.instance.currentUser;
}
Related
After i sign out, i try to log in again, yes it logs in succesfully but the problem is, i start to get error [cloud_firestore/permission-denied] but when i restart my application, it works again well. What am i missing?
PS: im logging in with Google.
This is my log in code:
Future signInWithGoogle() async {
// Trigger the authentication flow
final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
// Obtain the auth details from the request
final GoogleSignInAuthentication googleAuth =
await googleUser!.authentication;
// Create a new credential
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
// Once signed in, return the UserCredential
await _auth.signInWithCredential(credential);
}
This is my sign out code:
await _googleSignIn.signOut().then((value) async {
await widget.firebaseAuth.signOut().then((value) {
Navigator.pop(context);
});
}).onError((error, stackTrace) {
print(error);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text("ERROR!! TRY AGAIN"),
));
});
The cloud_firestore/permission-denied error comes from Firestore (the database), not from Firebase Authentication.
Most likely you have some realtime listeners in your code that require the user to be signed in, and those get rejected by the database once you sign the user out.
You can either remove the listeners by canceling the subscriptions, or you can ignore the errors, as the listeners are also canceled automatically after this error occurs.
In my case, I forgot to activate "google-sign in" as an authentication method in firebase.
I'm trying but failing to re-trigger the authentication steps that the user gets taken through when they authenticate themselves using Google sign-in, following deletion of the user. The deleted user simply gets signed in immediately (instead of being taken through the authentication steps), when using Google sign-in the second time. I want to be able to re-trigger the authentication steps for my own testing purposes.
Specifically, I've got a user who I've authenticated and signed in as per the FlutterFire documentation, i.e.
Future<UserCredential> signInWithGoogle() async {
// Trigger the authentication flow
final GoogleSignInAccount googleUser = await GoogleSignIn().signIn();
// Obtain the auth details from the request
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
// Create a new credential
final GoogleAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
// Once signed in, return the UserCredential
return await FirebaseAuth.instance.signInWithCredential(credential);
}
I then proceed to delete the user; again, as per the FlutterFire documentation, i.e.
try {
await FirebaseAuth.instance.currentUser.delete();
} catch on FirebaseAuthException (e) {
if (e.code == 'requires-recent-login') {
print('The user must reauthenticate before this operation can be executed.');
}
}
That works, insomuch as the user is no longer listed amongst the authenticated users in the Firebase console. However, if I now proceed to call signInWithGoogle() again, then instead of getting taken through the authentication steps again (i.e. being prompted to enter an email, password, etc.), the user simply gets signed in straight away. It's as if the user hasn't been properly deleted. How would I go about re-triggering the authentication steps?
You must also call GoogleSignIn().signOut() after the Firebase sign out or delete.
In my case, I had to reauthenticate firebase user inside the delete functions try-catch as currentUser() always return null AND GoogleSignIn().signOut() didnt work. Maybe a bug.
import 'package:google_sign_in/google_sign_in.dart';
import 'package:firebase_auth/firebase_auth.dart';
final GoogleSignIn _googleSignIn = GoogleSignIn();
final FirebaseAuth _auth = FirebaseAuth.instance;
//will need to sign in to firebase auth again as currentUser always returns null
//this try-catch block should be inside the function that deletes user
try {
//FirebaseUser user = await _auth.currentUser(); //returns null so useless
//signin to google account again
GoogleSignInAccount googleSignInAccount = await _googleSignIn.signIn();
GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
//get google credentials
AuthCredential credential = GoogleAuthProvider.getCredential(
idToken: googleSignInAuthentication.idToken,
accessToken: googleSignInAuthentication.accessToken);
//use credentials to sign in to Firebase
AuthResult authResult = await _auth.signInWithCredential(credential);
//get firebase user
FirebaseUser user = authResult.user;
print(user.email);
//delete user
await user.delete();
//signout from google sign in
await _googleSignIn.signOut();
} catch (e) {
print('Failed to delete user ' + e.toString());
}
I have a Flutter web app which uses Google sign in, managed with Firebase. If I run it with flutter run -d chrome, when I click on the sign in button, it pops up the Google sign in pane, however after writing in my email address, it says that it's an unsafe browser and that I should try to use another browser. After some research, I founda workaround, opening the localhost:5000 from a separate chrome window. In this case, the issue is that it doesn't show the popup.
I don't know if it has to do anything with the issue, but when I inspect the element it shows this warning:
The code I use to handle the sign-in:
import "package:firebase_auth/firebase_auth.dart";
import "package:google_sign_in/google_sign_in.dart";
class GoogleSignInService {
final GoogleSignIn _googleSignIn;
final FirebaseAuth _auth;
GoogleSignInService(this._googleSignIn, this._auth);
Future<FirebaseUser> handleSignIn() async {
FirebaseUser user;
bool isSignedIn = await _googleSignIn.isSignedIn();
if (isSignedIn) {
user = await _auth.currentUser();
} else {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken, idToken: googleAuth.idToken);
user = (await _auth.signInWithCredential(credential)).user;
}
return user;
}
}
I call the handlesignin in the onPressed of my sign in button. I use version 4.5.4 of the google_sign_in package. I have done everything suggested here: https://pub.dev/packages/google_sign_in_web
I have implemented Facebook and Google sign in.
But FireBase document says this will cause an error if the same user first signs up with Facebook and later try sign in with Google (with the same email).
So I follow doc and try to configure account linking.
But I do not know how to do.
Should I try link account every time user is logged in? Problem is I not know if the user already has signed in with another auth provider.
For example, the original code has:
Google:
void _signInWithGoogle() async {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
final FirebaseUser user = await _auth.signInWithCredential(credential);
}
Facebook:
void _signInWithFacebook() async {
final AuthCredential credential = FacebookAuthProvider.getCredential(
accessToken: _tokenController.text,
);
final FirebaseUser user = await _auth.signInWithCredential(credential);
}
Is correct to call every time in _signInWithFacebook() and _signInWithGoogle() :
user = await auth.linkWithCredential(credential);
For example:
void _signInWithFacebook() async {
final AuthCredential credential = FacebookAuthProvider.getCredential(
accessToken: _tokenController.text,
);
final FirebaseUser user = await _auth.signInWithCredential(credential);
user = await auth.linkWithCredential(credential); //new
}
How I can implement correctly?
Thanks!
When the user enters their email address to sign in, you'll want to use fetchSignInMethodsForEmail() to find out if that email address is already known.
If a user has already signed up with another provider, that's a good moment to ask them if they want to merge those accounts, and then call the account linking API.
Hi so i try to add firebase auth on my app, so i followed the documentations in here https://pub.dartlang.org/packages/firebase_auth from the plugin creators it self, It works well at first, but then i'm just ecounter an error or bug, its when i'm tried to add users instead of choose users that already login in my device, after add the users it will stuck forever in black sreen like the picture above, it not giving some error message it just stuck there. So is there anyone that already has same issues like me ? is there any solutions for this ? here is my code for handle the sign in
Future<FirebaseUser> _handleSignIn() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
GoogleSignInAccount googleUser = await _googleSignIn.signIn();
GoogleSignInAuthentication googleAuth = await googleUser.authentication;
FirebaseUser user = await _auth
.signInWithGoogle(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
Navigator.of(context).pushReplacementNamed('/HomeScreen');
await prefs.setString('accesToken', googleAuth.accessToken);
await prefs.setString('email', googleUser.email);
await prefs.setString('displayName', googleUser.displayName);
await prefs.setString('photoUrl', googleUser.photoUrl);
return user;
}
Most probably this happens because you have not enabled the Sign-in Method in Firebase Console.
Just enable Required Sign-in Methods and it should work fine.