how to keep user logged in - flutter

this is how I login using Google and firebase. but I couldn't figure it out as to how to keep the use logged in.. when the app restarts it log the user out automatically
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
Future<String> signInWithGoogle() async {
final GoogleSignInAccount? googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount!.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final authResult = await _auth.signInWithCredential(credential);
final User? user = authResult.user;
assert(!user!.isAnonymous);
final User? currentUser = _auth.currentUser;
assert(user!.uid == currentUser!.uid);
return 'signInWithGoogle succeeded: $user';
}

You can call await _auth.currentUser() at the start of your app to check the current user. Further you may want to store the token in shared preferences.

Firebase automatically persists the user credentials in the shared storage, and restores them when the app restarts. There's nothing you need to do for that.
What you will need to do though is listen for the authentication state as shown in the first code snippet in the documentation on getting the current user:
FirebaseAuth.instance
.authStateChanges()
.listen((User? user) {
if (user != null) {
print(user.uid);
}
});
This code needs to run when the app starts, so I typically have it in my top-level widget and then store the user in the state so that my build method can use it. By listening to auth state changes, the code is run automatically when the user sign-in state is restored at startup (which happens asynchronously, so may take a few moments) but also when the user would later be logged out (for example, if you disable the account in the Firebase Authentication console).

It may not be the best way to do it but this worked.
chooseLogin() {
if (_auth.currentUser == null) {
return const SignUo();
} else {
return const Splash();
}
}

Related

Google_sign_in Org_internal unable to login with different account

I'm working on an application for my organization. I was trying to implement oAuth with the google_sign_in package based on our google accounts.
The process for members to log in with accounts that belongs to the organization works fine. That's not the case with external emails.
I was expecting an error to be thrown in google prompt but I'm unable to log in with different at all. Seams that google tries to log me in instantly each time, leading to this screen each time:
I've tried using GoogleSignIn().signOut() or .deactivate() methods both of those did nothing to either remove the cache or retrigger the signing process.
Code responsible for log in:
class FirebaseAuthExternalIdentityProvider implements ExternalIdentityProvider {
final FirebaseAuth _firebaseAuth;
FirebaseAuthExternalIdentityProvider({required FirebaseAuth firebaseAuth})
: _firebaseAuth = firebaseAuth;
#override
Future<Result<GoogleSignInTokenWrapper>> signInWithGoogle() async {
final GoogleSignInAccount? googleAccount = await GoogleSignIn().signIn();
if (googleAccount == null) {
return Result.failure(Failure.signInProcessAborted());
}
final GoogleSignInAuthentication? googleAuthStatus =
await googleAccount.authentication;
final OAuthCredential _firebaseCredential = GoogleAuthProvider.credential(
accessToken: googleAuthStatus?.accessToken,
idToken: googleAuthStatus?.idToken,
);
try {
return Result.success(GoogleSignInTokenWrapper(
accessToken: await (await _firebaseAuth
.signInWithCredential(_firebaseCredential))
.user!
.getIdToken(),
));
} on FirebaseAuthException catch (cause) {
return Result.failure(Failure.firebaseSignInException(cause: cause));
} on Exception catch (cause) {
return Result.failure(Failure.unexpected(cause: cause));
}
}
}
Does someone know how to handle this problem? Changing the OAuth consent screen to External is the last thing I want to consider doing.
Thanks for any help in this matter!

How to logout facebook account for entring another account

I am using flutter facebook auth.
When I login for the first time came to enter email and password after that I logout and went to login again then it did not ask for email and password.
When I login for the first time came to enter email and password after that I logout and went to login again then it did not ask for email and password.
and its looks like it
this is my facebook login functionality
import 'package:cwc/ApiManager/preference.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
final FirebaseAuth _auth = FirebaseAuth.instance;
// final GoogleSignIn googleSignIn = GoogleSignIn();
String? fbName;
String? fbEmail;
String? fbImageUrl;
Future<String?> signInWithFacebook() async {
// Trigger the sign-in flow
final LoginResult loginResult = await FacebookAuth.instance.login();
// final GoogleSignInAccount? googleSignInAccount = await googleSignIn.signIn();
var a= await loginResult.message;
// Create a credential from the access token
final OAuthCredential facebookAuthCredential = FacebookAuthProvider.credential(loginResult.accessToken!.token);
print("facebookAuthCredential22 ${facebookAuthCredential.token}");
print("facebookAuthCredential33 ${facebookAuthCredential.accessToken}");
print("facebookAuthCredential44 ${facebookAuthCredential.rawNonce}");
// Once signed in, return the UserCredential
final UserCredential authResult =
await _auth.signInWithCredential(facebookAuthCredential);
final User? users = authResult.user;
final UserInfo? user = users!.providerData[0];
print("facebookAuthCredential11 $user");
// return FirebaseAuth.instance.signInWithCredential(facebookAuthCredential);
if (user != null) {
// Checking if email and name is null
// assert(user.email != null);
assert(user.displayName != null);
assert(user.photoURL != null);
Preferences.saveData("socialName", user.displayName.toString());
Preferences.saveData("socialEmail", user.email.toString());
Preferences.saveData("socialImage", user.photoURL.toString());
// Only taking the first part of the name, i.e., First Name
// if (googleName!.contains(" ")) {
// googleName = googleName!.substring(0, googleName!.indexOf(" "));
// }
assert(!users.isAnonymous);
assert(await users.getIdToken() != null);
final User? currentUser = _auth.currentUser;
assert(users.uid == currentUser!.uid);
print('signInWithFacebook succeeded: $user');
return '$user';
}
return null;
}
Future<void> signOutWithFacebook() async {
await FacebookAuth.instance.logOut();
print("User Signed Out");
}
You'll also need to sign out of Facebook explicitly by calling:
FacebookAuth.instance.logOut()
Also see:
How to properly sign out of Facebook on Android with Firebase?
The documentation of flutter_facebook_auth on signing out
You can call the setCustomParameters() method on FacebookAuthProvider.
And pass the consent parameter like so:
_facebookAuth.setCustomParameters({"consent":"select_account"});
You can read about the parameters you can pass to the consent on this answer

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.

Cannot sign-out from Facebook using flutter with firebase

I have a flutter app where I am authenticating with Facebook and firebase on iOS. However, I cannot get the login in page again although I am calling the logout function
I always get the facebook confirmation screen which has some text that inform me that I have already logged in.
How do I logout so that the next time I am ask to enter my email/pass
here is a snippet of my code
Future<FirebaseUser> signInWithFacebook();
final FirebaseAuth _auth = FirebaseAuth.instance;
Future<FirebaseUser> signInWithFacebook() async {
FirebaseUser user;
var result = await _facebookLogin
.logInWithReadPermissions(['email', 'public_profile']);
if (result.status == FacebookLoginStatus.loggedIn) {
FacebookAccessToken myToken = result.accessToken;
AuthCredential credential =
FacebookAuthProvider.getCredential(accessToken: myToken.token);
user = await _auth.signInWithCredential(credential);
}
return user;
}
Future<void> signOut() async {
await _facebookLogin.logOut();
await _auth.signOut();
}
Thanks for your help
Firebase saves the FirebaseUser object in cache so the user won't need to re-signin every time he leaves the app. So the signOut function should look like this:
Future<void> signOut() async {
await _facebookLogin.logOut();
await _auth.signOut();
_user = null;
}
And the FirebaseUser user; should be moved out of the signInWithFacebook function (I renamed it to _user).

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