Flutter Facebook Login Allowing to switch account - flutter

The app allows the user to sign in using Facebook, but I am having trouble with when the using wants to use a different Facebook account to sign in, this page will only show the continue button. Is there a way for the user to choose to use a different account for signing in?
Also, I have not really seem any error in the case for FacebookLoginStatus.error, what are some error handling that should be done to it?
I am new to flutter and coding, it will be helpful to point out if anything should be done differently or can be improve on.
onPressed: () async {
final facebookLogin = FacebookLogin();
final result = await facebookLogin.logIn(['email']);
switch (result.status) {
case FacebookLoginStatus.loggedIn:
try{
final token = result.accessToken.token;
AuthCredential credential =
FacebookAuthProvider.getCredential(accessToken: token);
FirebaseUser user = (await _auth.signInWithCredential(credential)).user;
if(user != null){
Navigator.pushReplacementNamed(context, Home.id);
}
} catch(e){
print(e);
}
break;
case FacebookLoginStatus.cancelledByUser:
print('cancelled');
break;
case FacebookLoginStatus.error:
print('error');
break;
}
},

having trouble with when the using wants to use a different Facebook account to sign in, this page will only show the continue button
I use FacebookLogin.logOut() to disconnect the user, just so the user can use a different account to login.
onPressed: () async {
final facebookLogin = FacebookLogin();
await facebookLogin.logOut(); // disconnect user
final FacebookLoginResult result =
await facebookLogin.logIn(['email', 'public_profile']);
switch (result.status) {
case FacebookLoginStatus.loggedIn:
try{
final token = result.accessToken.token;
AuthCredential credential =
FacebookAuthProvider.getCredential(accessToken: token);
FirebaseUser user = (await _auth.signInWithCredential(credential)).user;
if(user != null){
Navigator.pushReplacementNamed(context, Home.id);
}
} catch(e){
print(e);
}
break;
case FacebookLoginStatus.cancelledByUser:
alertMessage(context, 'cancelled'); // show dialog
break;
case FacebookLoginStatus.error:
alertMessage(context, 'error'); // show dialog
break;
}
},
what are some error handling that should be done to it?
You may prompt user of the login status messages:
void alertMessage(context, String message) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("Error"),
content: Text(message),
actions: [
FlatButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
},
)
],
)
);
}

add to first of code to login facebook
await FacebookAuth.instance.logOut();

Related

Flutter unable to login after create new account

After building the app, if I try to login it's working fine, but if I create a new account then try to login again, login is not working. I have seen after debugging that I'm getting token in _authenticate method. I think notifyListeners not working here but I don't know why?
I'm using the provider package in my flutter app. I have an Auth provider class where I'm saving data in firebase and also login by firebase. Below it's my provider class.
class Auth with ChangeNotifier {
String? _token;
late DateTime _expiryDate = DateTime.now();
late String _userId;
bool get isAuth {
return token != null;
}
String? get token {
if ((_expiryDate).isAfter(DateTime.now())) {
return _token;
}
return null;
}
Future _authenticate(String email, String password, String urlSegment) async {
var urlParse = Uri.parse(urlSegment);
try {
final response = await http.post(urlParse,
body: jsonEncode({
'email': email,
'password': password,
'returnSecureToken': true
})
);
final responseData = jsonDecode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
}
// set token and user id from firebase response
_token = responseData['idToken'];
_userId = responseData['localId'];
_expiryDate = DateTime.now()
.add(Duration(seconds: int.parse(responseData['expiresIn'])));
notifyListeners();
return responseData['idToken'];
} catch (error) {
rethrow;
}
}
Future login(String email, String password) async {
print(email);
String url = Constants.firebaseLoginUrl;
return _authenticate(email, password, url);
}
Future signup(String email, String password) async {
String url = Constants.firebaseSignupUrl;
return _authenticate(email, password, url);
}
}
In signUp page I have tried below code to create a new user
Future<void> signUpSubmit() async {
if (_formKey.currentState!.validate()) {
await Provider.of<Auth>(context, listen: false).signup(_email.text, _pass.text);
}
I have checked new data is saving perfectly.
In signUp page there has a login button, after click on login button I have redirect in login page,
TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const LoginPage()
),
);
},
child: const Text('Log in to access'),
)
After click on login I have redirect in login page, then tried login again but it's not working. In debug I'm getting token if I print(token) in _authenticate method.
In main.dart my consumer is looks like
child: Consumer<Auth>(
builder: (ctx,auth, _) => MaterialApp(
home: auth.isAuth ? const HomePage():const LoginPage(),
)
After create account if I rebuild app again then login is working? How I will solve this problem?
See you are redirecting directly in loginPage rather than via the main page ! Just redirect the login button to main page, in your main page there has condition
home: auth.isAuth ? const HomePage(): const LoginPage()
So, if it is auth false it will always redirect to the login page.
Change
MaterialPageRoute( builder: (context) => const LoginPage() ),
To
MaterialPageRoute( builder: (context) => const MainPage() ),

What to do after login but before essential user data gets returned in flutter

I have a flutter app that uses firebase for authentication.
return StreamBuilder<FirebaseUser>(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
if (snapshot.hasData) {
return HomeScreen();
} else {
return LoginScreen();
}
},
);
so basically as soon as user authenticates, this will take to the home screen. but i dont want that, i want to wait on another piece of data from my api, say onboarded, if onboarded == true then HomeScreen otherwise OnboardingScreen.
So the tricky part is before that data comes in, i want to stay on the login screen. how do i have the user stay on the LoginScreen? it seems the best way is to have another stream listen to the onboardedLoading and combine these 2 streams?
Make a dart file auth.dart, in that, paste this line of code,
final FirebaseAuth auth = FirebaseAuth.instance;
Future<FirebaseUser> handleSignInEmail(String email, String password) async {
AuthResult result = await auth.signInWithEmailAndPassword(email: email, password: password);
final FirebaseUser user = result.user;
assert(user != null);
assert(await user.getIdToken() != null);
final FirebaseUser currentUser = await auth.currentUser();
assert(user.uid == currentUser.uid);
print('signInEmail succeeded: $user');
return user;
}
Future<FirebaseUser> handleSignUp(email, password) async {
AuthResult result = await auth.createUserWithEmailAndPassword(email: email, password: password);
final FirebaseUser user = result.user;
assert (user != null);
assert (await user.getIdToken() != null);
return user;
}
In your login/ Sigup page, create an instance of my auth class:
var authHandler = new Auth();
In the onPressed () of your button
onPressed: () {
if(onboardedLoading==true){
authHandler.handleSignInEmail(emailController.text, passwordController.text)
.then((FirebaseUser user) {
Navigator.push(context, new MaterialPageRoute(builder: (context) => HomeScreen()));
}).catchError((e) => print(e));
}
}else{
//Show An Animation, such as CirclularProgressIndicator.
}
You can design a simple loading screen, then use Navigator.pushAndRemoveUntil() to whichever screen you need after getting AuthState.

Login to Flutter Facebook Login

I'm having a problem with the facebook login with flutter.
I followed a lot of tutorials but it's from 2018, 2019, so it doesn't match the version of flutter_facebook_login: ^3.0.0.
the process works very well when I launch it redirects me to facebook I enter my details I log in as MyFacebookName, the problem is that when I click on Ok it redirects me to the login page and it does not register the user on my Firebase console. Here is the code
// Facebook connection configuration
static final FacebookLogin facebookSignIn = new FacebookLogin();
String _message = 'Login or logout by pressing the buttons below.';
Future<void> _login() async {
final FacebookLoginResult result =
await facebookSignIn.logIn(['email']);
switch (result.status) {
FacebookLoginStatus.loggedIn box:
final FacebookAccessToken accessToken = result.accessToken;
_showMessage(''')
Sign in!
Token: ${accessToken.token}
User id: ${accessToken.userId}
Expires: ${accessToken.expires}
Permissions: ${accessToken.permissions}
Declined permissions: ${accessToken.declinedPermissions}
''');
break;
checkbox FacebookLoginStatus.cancelledByUser:
_showMessage("login cancelled by user.");
break;
checkbox FacebookLoginStatus.error:
"Something went wrong during the login process."
"Here's the error Facebook gave us: ${result.errorMessage}");
break;
}
}
Future<Null> _logOut() async {
await facebookSignIn.logOut();
_showMessage('Logout.');
}
void _showMessage(String message) {
setState(() {
_message = message;
});
}
//connection button
_buildSocialBtn(
() {
_login();
},

How to signIn with facebook in flutter?

How to signIn with facebook in flutter? I try like this but nothing appears. Something like the app froze but when I click back drop me 'CANCELED BY USER'.
How to make it work?
The problem is that nothing appears when you click only the application freezes and the only option is to go back and then throw it out 'CANCELED BY USER'.
var facebookLogin = FacebookLogin();
facebookLogin.logInWithReadPermissions(['email', 'public_profile']).then((result){
switch(result.status){
case FacebookLoginStatus.loggedIn:
FacebookAccessToken myToken = result.accessToken;
AuthCredential credential= FacebookAuthProvider.getCredential(accessToken: myToken.token);
FirebaseAuth.instance.signInWithCredential(credential).then((user){
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (context) => Menu()
));
}).catchError((e){
print(e);
});
break;
case FacebookLoginStatus.cancelledByUser:
print('CANCELED BY USER');
break;
case FacebookLoginStatus.error:
// TODO: Handle this case.
break;
}
}).catchError((e){
print(e);
});

How to handle Platform Exception when sign-in flow cancelled by user

I am unable to handle the platform exception when user presses cancel instead of logging in using the google sign in window.
I have even tried an if statement so to not run if signIn returns null, but that does not work either.
Future<void> _handleSignIn() async {
try {
await googleSignIn.signIn();
} catch (error) {
print(error);
}
}
What's not so obvious when authenticating with google, is that the process consist of three steps
_googleSignIn.signIn() // prompt window
googleAccount.authentication // obtaining the credentials
_auth.signInWithCredential(credential) // the actual authentication
// STEP 1
// This is where flow gets cancelled and it results in the `googleAccount` to be null
GoogleSignInAccount googleAccount = await _googleSignIn.signIn();
if (googleAccount == null) {
return null;
}
// STEP 2
// obtaining credentials (cached or via input)
GoogleSignInAuthentication googleAuthentication = await googleAccount.authentication;
AuthCredential credential = GoogleAuthProvider.getCredential(
idToken: googleAuthentication.idToken,
accessToken: googleAuthentication.accessToken,
);
// STEP 3
// the provider authentication
AuthResult authResult = await _auth.signInWithCredential(credential);
FirebaseUser user = authResult.user;
// RESULT
print (user.uuid);
The issue I had and seem like others may have too, is that when wrapping three steps in try catch block and not handling the null value from the first step, and the catch block would expect the error object and code property - which would be the case. Anyways here is how I handle it now.
// https://github.com/flutter/flutter/issues/26705
Future<FirebaseUser> signInWithGoogle() async {
FirebaseUser user;
var errorMessage;
try {
GoogleSignInAccount googleAccount = await _googleSignIn.signIn();
if (googleAccount == null) {
errorMessage = "CANCELLED_SIGN_IN";
return Future.error(errorMessage);
}
GoogleSignInAuthentication googleAuthentication = await googleAccount.authentication;
AuthCredential credential = GoogleAuthProvider.getCredential(
idToken: googleAuthentication.idToken,
accessToken: googleAuthentication.accessToken,
);
AuthResult authResult = await _auth.signInWithCredential(credential);
user = authResult.user;
return user;
}
catch(error) {
switch (error.code) {
case "ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL":
errorMessage = "Account already exists with a different credential.";
break;
case "ERROR_INVALID_CREDENTIAL":
errorMessage = "Invalid credential.";
break;
case "ERROR_INVALID_EMAIL":
errorMessage = "Your email address appears to be malformed.";
break;
case "ERROR_WRONG_PASSWORD":
errorMessage = "Your password is wrong.";
break;
case "ERROR_USER_NOT_FOUND":
errorMessage = "User with this email doesn't exist.";
break;
case "ERROR_USER_DISABLED":
errorMessage = "User with this email has been disabled.";
break;
case "ERROR_TOO_MANY_REQUESTS":
errorMessage = "Too many requests. Try again later.";
break;
case "ERROR_OPERATION_NOT_ALLOWED":
errorMessage = "Signing in with Email and Password is not enabled.";
break;
default:
errorMessage = "An undefined Error happened. ";
}
}
if (errorMessage != null) {
return Future.error(errorMessage);
}
return null;
}
And the google button
GoogleSignInButton(
onPressed: () async {
var isError = false;
var authService = Provider.of<AuthService>(context, listen: false);
await authService.signInWithGoogle().catchError((errorMessage) async {
isError = true;
if (errorMessage != 'CANCELLED_SIGN_IN') {
await showPopup(context, title: 'Validation', child: Text(errorMessage));
}
});
if (isError == false) {
Navigator.pushReplacementNamed(context, HomeScreen.routeName);
}
},
),
You can simply catch Error like -
Future<void> _handleSignIn() async {
await googleSignIn.signIn().catchError((e) {
print(e);
});
}