Flutter - Google Sign In uses previously signed in account (user) even after signing out and signing in with another account - flutter

When I hit "Sign in with Google", it does let me choose the account although somehow, the previous user gets loaded.
class GoogleSignInProvider extends ChangeNotifier {
GoogleSignIn? _googleSignIn;
GoogleSignInAccount? _user;
GoogleSignInAccount get user => _user!;
bool _isGoogleLogin = false;
final _auth = FirebaseAuth.instance;
Future signInWithGoogle(context) async {
try {
_googleSignIn = GoogleSignIn();
final googleUser = await _googleSignIn!.signIn();
if (googleUser == null) {
return;
}
_user = googleUser;
final googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
var authCredential = await _auth.signInWithCredential(credential);
_isGoogleLogin = true;
if (authCredential.user != null) {
final snapshot = await FirebaseFirestore.instance
.collection('users')
.doc(authCredential.user!.uid)
.get();
if (!snapshot.exists) {
var userId = authCredential.user!.uid;
FirebaseFirestore.instance.collection('users').doc(userId).set({
"email": googleUser.email,
"workoutsCount": 0,
"lastWorkoutDate": null
});
}
}
notifyListeners();
Navigator.of(context).pushNamed('/dashboard');
} on FirebaseAuthException catch (e) {
showSnackBar(context, e);
} catch (e) {
print('ERROR = ');
print(e);
}
}
Future<void> signOut(context) async {
try {
if (_isGoogleLogin) {
final googleCurrentUser =
GoogleSignIn().currentUser ?? await GoogleSignIn().signIn();
if (googleCurrentUser != null) {
await GoogleSignIn().disconnect().catchError((e, stack) {
FirebaseCrashlytics.instance.recordError(e, stack);
});
}
}
await _auth.signOut();
} catch (e) {
showSnackBar(context, e);
} finally {
_isGoogleLogin = false;
Navigator.of(context).pushNamedAndRemoveUntil(
'/register_login', (Route<dynamic> route) => false);
}
}
Is there something wrong with this code??

Can you try to disconnect the account before signing out:
GoogleSignIn _googleSignIn = GoogleSignIn();
await _googleSignIn.disconnect();
await FirebaseAuth.instance.signOut();

You are using firebase auth then please use thsi for signout user :
How to Signout a user in Flutter with Firebase authentication

Remove if (_isGoogleLogin) from your signOut function. googleCurrentUser will check the consitionn and responses based on the result.

First Create a Global variable
FirebaseAuth firebaseAuth = FirebaseAuth.instance;
GoogleSignIn googleSignIn = GoogleSignIn();
Make sure you are using the above variable for login and logout
final googleCurrentUser = firebaseAuth.currentUser;
if (googleCurrentUser != null) {
googleSignIn.signOut();
await firebaseAuth.signOut();
}
User above code for signout user

Related

How to save the user email and name in database while signing in with google?

I am using google auth and i want to save user data in database...How can i get user details here and save it to database?
Future<void> signUpWithGoogle(
BuildContext context,
bool mounted,
) async {
final googleSignIn = GoogleSignIn();
final googleUser = await googleSignIn.signIn();
if (googleUser == null) return;
final googleAuth = await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
try {
await FirebaseAuth.instance.signInWithCredential(credential);
FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.set({
//
});
if (mounted) return;
InfoBox.show(context, InfoBox.success, "Signed In With Google");
} on Exception catch (e) {
if (mounted) return;
InfoBox.show(context, InfoBox.success, e.toString());
}
}
Please modify the code under your try block as below
try {
final authResult = await FirebaseAuth.instance.signInWithCredential(credential);
if (authResult.additionalUserInfo!.isNewUser) {
await FirebaseFirestore.instance
.collection('Users')
.doc(authResult.user!.uid)
.set({
"Name": authResult.user!.displayName,
"Email": authResult.user!.email,
});
}
if (mounted) return;
InfoBox.show(context, InfoBox.success, "Signed In With Google");
} on Exception catch (e) {
if (mounted) return;
InfoBox.show(context, InfoBox.success, e.toString());
}
Please accept the solution if it solves your problem
Inside your try block, you have to get UserCredential which gives the User object data to be saved in the next line.
try{
UserCredential userCredential =
await FirebaseAuth.instance.signInWithCredential(credential);
User user = userCredential.user; // User is updated version of FirebaseUser
FirebaseFirestore.instance.collection('users').doc(user.uid).set(/*Add Mapped User object*/);}
You can use user object to get all the necessary data.

I'm trying to signOut with google in Flutter with Firebase and it doesn't work

I'm using Flutter with Firebase. When I try to logout with email and password, it works good but when I try with google it doesn't work.
Here is my code:
`
try {
switch (user.providerData[0].providerId) {
case 'password':
await FirebaseAuth.instance.signOut();
break;
case 'google.com':
final GoogleSignIn googleSignIn = GoogleSignIn();
await googleSignIn.signOut();
break;
}
} on FirebaseAuthException catch (e) {
showAuthException(e, context);
}
`
I'm trying this
`
try {
switch (user.providerData[0].providerId) {
case 'password':
await FirebaseAuth.instance.signOut();
break;
case 'google.com':
final GoogleSignIn googleSignIn = GoogleSignIn();
await googleSignIn.signOut();
break;
}
} on FirebaseAuthException catch (e) {
showAuthException(e, context);
}
`
Please refer to this code :) and this will do the trick.
your Code:
final GoogleSignIn googleSignIn = GoogleSignIn();
await googleSignIn.signOut();
the problem is you have created googleSignIn variable and signOut from that variable.
you can also try to check using googleSignIn.isSignedIn(); this will return bool value.
Working Code.
class GoogleServiceProvider extends ChangeNotifier {
static final GoogleSignIn _googleSignIn = GoogleSignIn(); // <----
GoogleSignInAccount? _user;
GoogleSignInAccount? get user => _user;
Future<GoogleSignInAccount?> logInWithGmail() async {
final googleUser = await _googleSignIn.signIn();
if (googleUser != null) {
_user = googleUser;
notifyListeners();
}
return null;
}
Future logOut() async {
await _googleSignIn.signOut();
notifyListeners();
}
}

Flutter Google Sign In error after canceling Choose an account pop-up

After clicking sign in, choose an account pop comes up but if the user pressed back or outside of the pop-up it throws an error.
Error -
Sign in class -
class GoogleSignInProvider extends ChangeNotifier {
final googleSignIn = GoogleSignIn();
GoogleSignInAccount? _user;
GoogleSignInAccount get user => _user!;
Future googleLogin() async {
await googleSignIn.signOut();
final googleUser = await googleSignIn.signIn();
if (googleUser == null) return;
_user = googleUser;
final googleAuth = await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken, idToken: googleAuth.idToken);
await FirebaseAuth.instance.signInWithCredential(credential);
notifyListeners();
}
}
Sign out button -
TextButton(
onPressed: () async {
final googleCurrentUser = GoogleSignIn().currentUser;
if (googleCurrentUser != null) {
await GoogleSignIn().disconnect();
}
FirebaseAuth.instance.signOut();
Navigator.pop(context);
},
child: const Text(
'Yes',
style: TextStyle(color: primaryColor),
))
Instead of if (googleUser == null) return; try using if (googleUser == null) return null;.
Here is my sign in method;
Future<UserCredential?> signInWithGoogle() async {
final _googleSignIn = GoogleSignIn();
await _googleSignIn.disconnect().catchError((e, stack) {
print(e);
});
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
// handling the exception when cancel sign in
if (googleUser == null) return null;
// 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,
);
return await FirebaseAuth.instance.signInWithCredential(credential);
}
The sign out method;
Future signOut() async {
var result = await FirebaseAuth.instance.signOut();
return result;
}
This only happens in debugging, in release this won't be an issue.

Flutter - googleapis - How to read email with Gmail Api

Flutter - How to read email with Gmail Api?
I was looking into googleapis https://pub.dev/packages/googleapis but there is no documentation on how it is actually done.
Can someone point me to a an example or a tutorial?
Here is a complete example:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:zapit/models/appState.dart';
import 'package:googleapis/gmail/v1.dart' as gMail;
class GmailApiScreen extends StatefulWidget {
#override
_GmailApiScreenState createState() => _GmailApiScreenState();
}
class _GmailApiScreenState extends State<GmailApiScreen> {
gMail.GmailApi gmailApi;
List<gMail.Message> messagesList = [];
Future waitForInit;
#override
void initState() {
super.initState();
waitForInit = init();
}
init() async {
final authHeaders = await AppState.state.googleUser.authHeaders;
final authenticateClient = GoogleAuthClient(authHeaders);
gmailApi = gMail.GmailApi(authenticateClient);
gMail.ListMessagesResponse results =
await gmailApi.users.messages.list("me");
for (gMail.Message message in results.messages) {
gMail.Message messageData =
await gmailApi.users.messages.get("me", message.id);
messagesList.add(messageData);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("email")),
body: buildFutureBuilder(),
);
}
FutureBuilder buildFutureBuilder() {
return FutureBuilder(
future: waitForInit,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// If the Future is complete, display the preview.
List<Widget> messageTxt = [];
for (var m in messagesList) {
messageTxt.add(Text(m.snippet));
}
return Column(
children:messageTxt,
);
} else {
// Otherwise, display a loading indicator.
return Center(child: CircularProgressIndicator());
}
});
}
}
class GoogleAuthClient extends http.BaseClient {
final Map<String, String> _headers;
final http.Client _client = new http.Client();
GoogleAuthClient(this._headers);
Future<http.StreamedResponse> send(http.BaseRequest request) {
return _client.send(request..headers.addAll(_headers));
}
}
the googleUser is created with calling ensureLoggedInOnStartUp in the following code:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:googleapis/gmail/v1.dart' as gMail;
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn.standard(scopes: [gMail.GmailApi.GmailReadonlyScope]);
Future<GoogleSignInAccount> ensureLoggedInOnStartUp() async {
// That class has a currentUser if there's already a user signed in on
// this device.
try {
GoogleSignInAccount googleSignInAccount = googleSignIn.currentUser;
if (googleSignInAccount == null) {
// but if not, Google should try to sign one in whos previously signed in
// on this phone.
googleSignInAccount = await googleSignIn.signInSilently();
if (googleSignInAccount == null) return null;
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final UserCredential authResult =
await _auth.signInWithCredential(credential);
final User user = authResult.user;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final User currentUser = await _auth.currentUser;
assert(user.uid == currentUser.uid);
return googleSignInAccount;
}
} catch (e) { //on PlatformException
print(e);
}
return null;
}
Future<GoogleSignInAccount> signInWithGoogle() async {
try {
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
// throws FirebaseException when no internet connection
final UserCredential authResult = await _auth.signInWithCredential(credential);
final User user = authResult.user;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final User currentUser = await _auth.currentUser;
assert(user.uid == currentUser.uid);
return googleSignInAccount;
} catch (e,s) {
print(e);
print(s);
return null;
}
}
void signOutGoogle() async {
await googleSignIn.signOut();
print("User Sign Out");
}

Can't catch Flutter exception in GoogleSignIn

I'm trying to implement Google Sign-In in a Flutter application but all the exception that I try to catch are not being caught. I don't know why. I have tried different methots to catch them but nothing.
This is my code:
Future signInWithGoogle() async {
GoogleSignInAccount googleSignInAccount;
try {
googleSignInAccount = await googleSignIn.signIn().then((res) {
print("success");
return null;
}, onError: (e) {
print("${e.toString()}");
return null;
});
} catch (err) {
print("${err.toString()}");
}
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final AuthResult authResult = await _auth.signInWithCredential(credential);
final FirebaseUser user = authResult.user;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final FirebaseUser currentUser = await _auth.currentUser();
assert(user.uid == currentUser.uid);
return 'signInWithGoogle succeeded: $user';
}
The exception is always thrown on line googleSignInAccount = await googleSignIn.signIn()
As you can see I try to catch exceptions in many ways but none of them actually works.
I see a problem with your sample code and its the .then call ...
googleSignInAccount = await googleSignIn.signIn().then((res) {
print("success");
return null;
}, onError: (e) {
print("${e.toString()}");
return null;
});
you cannot do both an await and a .then typically its one or the other. For the try/catch to work remove the .then
try {
googleSignInAccount = await googleSignIn.signIn();
} catch(err) {
...
}