Flutter Web Google Sign In - flutter

I try to implement a signIn with Google in Flutter Web. I use GoogleSignn 4.1.1 and Firebase Auth 0.15.4. I do not get any error message. It just does not pop up.
I registered the web app in Firebase (Added Dependencies) and even added the <meta> Tag with the google-signin-client_id
The Firebase Auth with Google works when I run it on Android
I also ran the Example App from GoogleSignIn in Web. It also does not pop up.
This is my Login Code (Works on Android)
final FirebaseAuth _auth = FirebaseAuth.instance;
FirebaseUser user = await _auth.currentUser();
if (user != null) {
log.d('alreadyLoggedIn');
} else {
final GoogleSignIn _googleSignIn = GoogleSignIn(clientId: Constants.GOOGLE_SIGN_IN_CLIENT_ID);
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
await _auth.signInWithCredential(credential);
user = await _auth.currentUser();
assert(user.email != null);
assert(user.displayName != null);
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
}
return user;
}
I hope someone knows how this can be fixed.

Have you followed all of the instructions (including adding OAuth ID to index.html) from this page?
https://pub.dev/packages/google_sign_in_web
You get your CLIENT ID from https://console.developers.google.com/apis/credentials
You also have to run from terminal like this, for it to work on localhost in debug:
flutter run -d chrome --web-hostname localhost --web-port 5000
The default authorised port is 5000, you can add other URIs on the same page you got your CLIENT ID (e.g.8764367243864-987523.apps.googleusercontent.com), it's under "Authorised JavaScript origins"
https://console.developers.google.com/apis/credentials)

Related

Google sign in with Firebase on Flutter logs in without selecting google account or authorizing it

I'm trying to implement a sign in with google on a flutter app using firebaseAuth, the user can log in just fine, but I've realized that the app doesn't ask for a google account nor does it ask for authorization if I delete the account in the firebase console.
This is my google Sign in method:
Future<UserCredential> signInWithGoogle() async {
final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
final GoogleSignInAuthentication? googleAuth =
await googleUser?.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
return await FirebaseAuth.instance.signInWithCredential(credential);
}
I've tried changing the way the sign out happens but nothing changed, currently using FirebaseAuth.instance.signOut()
For signing out.

Flutter Google sign-in error on first time login

I am using google_sign_in plugin. It's running fine if the user has already account logged in and user just needs to select his account.
But when a new google account is added just before the login, then googleUser remains null and hence it throws exception.
Here's the code.
Future<UserCredential> signInWithGoogle() async {
//here googleUser remains null on first time login.....
GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
// Obtain the auth details from the request
final GoogleSignInAuthentication? googleAuth =
await googleUser?.authentication;
final OAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth?.accessToken,
idToken: googleAuth?.idToken,
);
// Once signed in, return the UserCredential
return await FirebaseAuth.instance.signInWithCredential(credential);
}

Is it possible to fetch emails from pop3 using sign in with google rather than app password?

I am fetching emails from pop3 with app password which is working perfectly fine. Can I replace app password with sign-in with google? I am using enough_email package.
I am done like this:
await popClient.connectToServer(host, port, isSecure: true);
await popClient.login(email!, token!);
and signing with google like this:
FirebaseAuth auth = FirebaseAuth.instance;
User? user;
final GoogleSignIn googleSignIn = GoogleSignIn();
final GoogleSignInAccount? account = await googleSignIn.signIn();
final GoogleSignInAuthentication authentication = await account.authentication;
final AuthCredential authCredential = GoogleAuthProvider.credential(
accessToken: authentication.accessToken,
idToken: authentication.idToken,
);
final UserCredential userCredential = await auth.signInWithCredential(authCredential);
user = userCredential.user;
I already tried to login with accessToken and idToken but getting PopException -ERR [AUTH] Username and password not accepted
After some research I found the following documents
https://developers.google.com/gmail/imap/xoauth2-protocol
https://developers.google.com/identity/protocols/oauth2
that leads me to the right direction. To authenticate client using sign-in with google. Here is my code for reference:
ImapClient imapClient = ImapClient();
await imapClient.connectToServer("imap.google.com", 993, isSecure: true);
await imapClient.authenticateWithOAuth2(user, accessToken);
await imapClient.selectInbox();
final FetchImapResult result = await imapClient.fetchRecentMessages();
List<MimeMessage> mimeMessages = result.messages;
for (MimeMessage mimeMessage in mimeMessages) {
print(mimeMessage.decodeTextPlainPart());
}
await imapClient.disconnect();
user: email address
accessToken: google sign-in authentication token

How to obtain the refreshToken when google sign in with Flutter / Firebase

I've already did the google sign with the firebase flutter toolkit. When sign in is done, I receive the idToken to read/write on the database.
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
Future<String> signInWithGoogle() async {
await Firebase.initializeApp();
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final UserCredential authResult = await _auth.signInWithCredential(credential);
final User user = authResult.user;
final idToken = await user.getIdToken();
}
The problem is, I need to auto login user when he opens the app again. So, when I sign in with google, I do not receive the refresh token, needed to get the new valid idToken, as the Doc.
How can I get the refreshToken ?
You can use SharedPreferences to set a bool value when a user is logged in from google and check the value when the app restarts. Don't forget to remove this value from shared preferences when user logged out.
I'm pretty sure googl_sign_in keeps the refresh token internally and you always receive a valid idToken. If it's about to expire, you can force renewal.
Answering your direct question about refreshToken:
You can create your own implementation of the google_sign_in class. In the end it's just an OAuth token. Here's a web implementation of a custom google_sign_in service: https://stackoverflow.com/a/69746036/5492496
I'm pretty sure you can do the same for Android & iOS using web view, you will loose the single click functionality on Android though.

Make flutter app force a user to choose an account with FirebaseAuth and GoogleSignInAuthentication

I want to force a user to select one of his account during login time. Is there any method to do so? I haven't found any configuration like prompt=select_account+consent.
Now, with these codes, after a user logout and then try to login again, it will automatically sign in with the selected account, there is no window showing up for user to select an account.
pubspec.yaml
firebase_auth: ^0.8.1+4
google_sign_in: ^3.2.4
Login part
GoogleSignInAccount googleUser = await _googleSignIn.signIn();
GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
user = await _auth.signInWithCredential(credential);
Logout part
await FirebaseAuth.instance.signOut();
GoogleSignIn _googleSignIn = GoogleSignIn();
await _googleSignIn.signOut();
Use GoogleSignInAccount.disconnect() before signing out to revoke the previous authentication:
await _googleSignIn.disconnect();
await FirebaseAuth.instance.signOut();
Harold's answer used to work for me, but recently the GoogleSignIn().currentUser appears null for some devices I tested, and then the disconnect function won't work. So, what solved that problem was ensuring it is signed in to Google.
final googleCurrentUser =
GoogleSignIn().currentUser ?? await GoogleSignIn().signIn();
if (googleCurrentUser != null)
await GoogleSignIn().disconnect().catchError((e, stack) {
FirebaseCrashlytics.instance.recordError(e, stack);
});
await _auth.signOut();
A simple way to go about it :-
In your sign out method just use
_auth.signOut();
Now inside Google Sign In package, inside google_sign_in.dart
Future<GoogleSignInAccount> signIn() {
final Future<GoogleSignInAccount> result =
_addMethodCall(GoogleSignInPlatform.instance.signIn, canSkipCall: false);
bool isCanceled(dynamic error) =>
error is PlatformException && error.code == kSignInCanceledError;
return result.catchError((dynamic _) => null, test: isCanceled);
}
Find the above method & set the canSkipCall parameter as false
final Future<GoogleSignInAccount> result =
_addMethodCall(GoogleSignInPlatform.instance.signIn, canSkipCall: false);
This will enable choosing a user every time you try to sign in