How to properly catch exception from FirebaseAuthException - firebase

My Editor(Vs code) keeps catching this exception even when it's already caught in my code. And the code works fine after the exception is caught.
The exception Log
" Exception has occurred. PlatformException
(PlatformException(firebase_auth,
com.google.firebase.auth.FirebaseAuthUserCollisionException: An
account already exists with the same email address but different
sign-in credentials. Sign in using a provider associated with this
email address., {code: account-exists-with-different-credential,
additionalData: {authCredential: {providerId: facebook.com,
signInMethod: facebook.com, token: 0000000}, email: #######gmail.com},
message: An account already exists with the same email address but
different sign-in credentials. Sign in using a provider associated
with this email address.}, null)) "
My Facebook Login Code
Future<void> logInWithFaceBook() async {
try {
final FacebookLoginResult result = await _facebookLogin.logIn(['email']);
final fbToken = result.accessToken.token;
if (result.status == FacebookLoginStatus.loggedIn) {
final facebookCredential =
firebase_auth.FacebookAuthProvider.credential(fbToken);
await _firebaseAuth.signInWithCredential(facebookCredential);
}
} on firebase_auth.FirebaseAuthException catch (e) {
await fbLinkPendingCredential(e);
}
}

Related

Flutter FirebaseAuth: SignUp unable to handle error when the email address is used by another user

My code here, and the error pointed at -> await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: email.trim(), password: password.trim()); - in code below
Future SignUp() async {
try {
UserCredential result = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: email.trim(), password: password.trim());
User user = result.user;
return user;
} on FirebaseAuthException catch (e) {
print(e);
if (e.code == 'email-already-in-use') {
setState(
() // setState rebuilds the entire build by modifying the code inside it
{
error = e.toString();
EmailExists =
true; //sets the emailExists variable to 'true' and rebuild
});
}
}
}
Error:
PlatformException (PlatformException(firebase_auth, com.google.firebase.auth.FirebaseAuthUserCollisionException: The email address is already in use by another account., {message: The email address is already in use by another account., additionalData: {}, code: email-already-in-use}, null))
By default Firebase Authentication only allows a single user to register with a specific email address in a project. When a second user tries to register with the same email address, you get the error that you have and you'll need to handle that scenario in your code. Typically you'll tell the user that the email address has already been registered and either ask them for their password, or tell them to use another email address.
If you want to allow multiple users to register with the same email address, you can enable that by changing the Multiple accounts per email address setting in the Sign-in methods pabel of the Firebase console.

what are the error codes for Flutter Firebase Auth Exception?

I have tried to read this thread List of Authorisation errors with Firebase login , and also I have tried to search, but I just can find admin SDK authentication error in here here
those error code from those links are different from the error code for Firebase Auth for Flutter app
I mean, I need the error codes in here
Future<void> signInUsingEmail({required String email, required String password}) async {
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} on FirebaseAuthException catch (error) {
// I need the error.code in here
print(error.code);
}
could I know all available error codes? so I can write my own error message in my own language. as for now, I can only catch these error codes below
"too-many-requests"
"wrong-password"
"network-request-failed"
what else?
For the signInWithEmailAndPassword method for Flutter, you will find the error codes in the firebase_auth package documentation.
They are actually the same than the JS SDK ones: https://firebase.google.com/docs/reference/js/firebase.auth.Auth#error-codes_12
For anyone that does not like clicking on links:
signInWithEmailAndPassword
wrong-password: Thrown if the password is invalid for the given email, or the account corresponding to the email doesn't have a password set.
invalid-email: Thrown if the email address is not valid.
user-disabled: Thrown if the user corresponding to the given email has been disabled.
user-not-found: Thrown if there is no user corresponding to the given email.
createUserWithEmailAndPassword
email-already-in-use: Thrown if there already exists an account with the given email address.
invalid-email: Thrown if the email address is not valid.
operation-not-allowed: Thrown if email/password accounts are not enabled. Enable email/password accounts in the Firebase Console, under the Auth tab.
weak-password: Thrown if the password is not strong enough.
signInWithCredential
account-exists-with-different-credential: Thrown if there already exists an account with the email address asserted by the credential. Resolve this by calling fetchSignInMethodsForEmail and then asking the user to sign in using one of the returned providers. Once the user is signed in, the original credential can be linked to the user with linkWithCredential.
invalid-credential: Thrown if the credential is malformed or has expired.
operation-not-allowed: Thrown if the type of account corresponding to the credential is not enabled. Enable the account type in the Firebase Console, under the Auth tab.
user-disabled: Thrown if the user corresponding to the given credential has been disabled.
user-not-found: Thrown if signing in with a credential from EmailAuthProvider.credential and there is no user corresponding to the given email.
wrong-password: Thrown if signing in with a credential from EmailAuthProvider.credential and the password is invalid for the given email, or if the account corresponding to the email does not have a password set.
invalid-verification-code: Thrown if the credential is a PhoneAuthProvider.credential and the verification code of the credential is not valid.
invalid-verification-id: Thrown if the credential is a PhoneAuthProvider.credential and the verification ID of the credential is not valid.id.
reauthenticateWithCredential
user-mismatch: Thrown if the credential given does not correspond to the user.
user-not-found: Thrown if the credential given does not correspond to any existing user.
invalid-credential: Thrown if the provider's credential is not valid. This can happen if it has already expired when calling link, or if it used invalid token(s). See the Firebase documentation for your provider, and make sure you pass in the correct parameters to the credential method.
invalid-email: Thrown if the email used in a EmailAuthProvider.credential is invalid.
wrong-password: Thrown if the password used in a EmailAuthProvider.credential is not correct or when the user associated with the email does not have a password.
invalid-verification-code: Thrown if the credential is a PhoneAuthProvider.credential and the verification code of the credential is not valid.
invalid-verification-id: Thrown if the credential is a PhoneAuthProvider.credential and the verification ID of the credential is not valid.
signInWithAuthProvider
user-disabled: Thrown if the user corresponding to the given email has been disabled.
signInAnonymously
operation-not-allowed: Thrown if anonymous accounts are not enabled. Enable anonymous accounts in the Firebase Console, under the Auth tab.
signInWithEmailLink
expired-action-code: Thrown if OTP in email link expires.
invalid-email: Thrown if the email address is not valid.
user-disabled: Thrown if the user corresponding to the given email has been disabled.
So I created this gist
And it's basically a handler for some common firebase auth exceptions.
This is an example on how to use it
Future createUser(String email, String password) async {
try {
UserCredential customUserCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: email, password: password);
return customUserCredential.user!.uid;
} on FirebaseAuthException catch (authError) {
throw CustomAuthException(authError.code, authError.message!);
} catch (e) {
throw CustomException(errorMessage: "Unknown Error");
}
TextButton(
onPressed: () async {
try {
//final user = FirebaseAuth.instance.currentUser;
final email = _emailController.text;
final password = _passwordController.text;
// await FirebaseAuth.instance // final userCredential =
// .signInWithEmailAndPassword(
// email: email, password: password);
AuthService.firebase()
.logIn(email: email, password: password);
final user = AuthService.firebase().currentUser;
if (user?.isEmailVerified ?? false) {
Navigator.of(context).pushNamedAndRemoveUntil(
emailRoute, (route) => false);
} else {
Navigator.of(context)
.pushNamedAndRemoveUntil(noteRoute, (route) => false);
}
//devtools.log(userCredential.toString());
//This line of text may not work to print data
// print(userCredential.toString());
} on FirebaseAuthException catch (e) {
if (e.code == 'network-request-failed') {
showErrorDialog(context, 'No Internet Connection');
//devtools.log('No Internet Connection');
} else if (e.code == "wrong-password") {
return showErrorDialog(
context, 'Please Enter correct password');
//devtools.log('Please Enter correct password');
//print('Please Enter correct password');
} else if (e.code == 'user-not-found') {
showErrorDialog(context, 'Email not found');
// print('Email not found');
} else if (e.code == 'too-many-requests') {
return showErrorDialog(
context, 'Too many attempts please try later');
//print('Too many attempts please try later');
} else if (e.code == 'unknwon') {
showErrorDialog(
context, 'Email and password field are required');
//print('Email and password field are required');
} else if (e.code == 'unknown') {
showErrorDialog(
context, 'Email and Password Fields are required');
//print(e.code);
} else {
print(e.code);
}
}
},
child: const Text('Login')),

showDialog() - Attempting to trigger dialog modal based on error message retrieved from Firebase Authentication API call

I'm trying to establish error handling for my app.
Backend is Firebase.
Intended functionality:
In the case the API call returns a response with an error message,
make the determination of what the error message is and display the text that is appropriate for that error message and
deploy a modal to display a particular error message according to the error response from the API call.
I believe that the HttpException logic established in the Auth class is not being passed over via the provider so instead the method on HttpException catch (error) is calling on HttpException and not the logic established within the Auth provider.
The code still runs bot only the terminal displays the error. Modal does not deploy.
Here is an example of an error API call I receive:
I/flutter (29822): {error: {code: 400, message: EMAIL_NOT_FOUND, errors: [{message: EMAIL_NOT_FOUND, domain: global, reason: invalid}]}}
I'm attempting to target the message within the error response
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
//if the API call retrieves an error
throw HttpException(
//throw custom error handling method
message: responseData['error']['message'],
//display the error message returned in the API call (the value assigned to the message within the error array)
);
}
And then pass it through the Provider.
Provider that holds API calls:
class Auth with ChangeNotifier {
String _token;
DateTime _tokenExpirationDate;
String _userID;
final String apiKey = #; //redacted
//AUTHENTICATION method - extracted to reduce reuse of code
Future<void> _authenticate(
{String email, String password, String urlSegment}) async {
final url = Uri.parse(
'https://identitytoolkit.googleapis.com/v1/accounts:$urlSegment?key=$apiKey');
//.parse method allows the use of the full url
try {
final response = await http.post(
url,
body: json.encode({
'email': email,
'password': password,
'returnSecureToken': true,
}),
);
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
//if the API call retrieves an error
throw HttpException(
//throw custom error handling method
message: responseData['error']['message'],
//display the error message returned in the API call (the value assigned to the message within the error array)
);
}
print(response.statusCode);
} catch (error) {
throw error;
}
}
//AUTHENTICATION CREATE API call - Register user
Future<void> signup(String email, String password) async {
_authenticate(
email: email,
password: password,
urlSegment: 'signUp',
);
}
//AUTHENTICATION READ API call - user sign in
Future<void> signin(String email, String password) async {
_authenticate(
email: email,
password: password,
urlSegment: 'signInWithPassword',
);
}
}
Standardized error handling class:
class HttpException implements Exception {
HttpException({this.message});
final String message;
#override
String toString() {
return message;
}
}
Authentication card that displays UI and interaction logic:
//VOID function to display a dialog modal. We will use this to display a dialog modal and populate the message with whatever error message the API call returns
void _errorDialog({String message}) {
showDialog(
//in the case that an error occurs, by us putting the return in front of showDialog, showDialog will fulfill that Future in case of the error. If there is no error the .then will fulfill the expected Future value
context: context,
builder: (ctx) => AlertDialog(
title: Text('An error occurred'),
content: Text(message),
//we will change the value of message to display according to what the API call returns
actions: [
TextButton(
child: Text('Okay'),
onPressed: () {
Navigator.of(ctx).pop();
},
),
],
),
);
}
//SUBMIT button logic
Future<void> _submit() async {
if (!_formKey.currentState.validate()) {
// Invalid!
return;
}
//Invalid response from user
_formKey.currentState.save();
setState(() {
_isLoading = true;
});
//ATTEMPT TO MAKE API CALLS BASED ON ENUM STATE OF DISPLAY
try {
if (_authMode == AuthMode.Login) {
//USER LOGIN
//call the sign in (read) API
await Provider.of<Auth>(context, listen: false).signin(
_authData['email'],
_authData['password'],
);
} else {
//REGISTER USER
//call the register (create) API
await Provider.of<Auth>(context, listen: false).signup(
_authData['email'],
_authData['password'],
);
}
} on HttpException catch (error) {
//we are conducting a filter on the type of errors we want to handle within this block.
//here we are calling on the HttpException
var httpErrorMessage = 'Could not login or sign up.';
//all of the following error messages were retrieved from the Firebase Auth API documentation
if (error.toString().contains('EMAIL_EXISTS')) {
//if the API call retrieves a value of 'EMAIL_EXISTS' in the error message
httpErrorMessage = 'This email is alreary in use';
//display the above error message
} else if (error.toString().contains('INVALID_EMAIL')) {
//if the API call retrieves a value of 'INVALID_EMAIL' in the error message
httpErrorMessage = 'This is not a valid email.';
//display the above error message
} else if (error.toString().contains('INVALID_EMAIL')) {
//if the API call retrieves a value of 'INVALID_EMAIL' in the error message
httpErrorMessage = 'This is not a valid email.';
//display the above error message
} else if (error.toString().contains('EMAIL_NOT_FOUND')) {
//if the API call retrieves a value of 'EMAIL_NOT_FOUND' in the error message
httpErrorMessage = 'Could not find a user with that email.';
//display the above error message
} else if (error.toString().contains('INVALID_PASSWORD')) {
//if the API call retrieves a value of 'INVALID_PASSWORD' in the error message
httpErrorMessage = 'Invalid password.';
//display the above error message
}
_errorDialog(message: httpErrorMessage);
//call the error dialog method
//display in the message whatever defined message to display according to the API error response
} catch (error) {
//calling on the error that was established in the Auth class catch(error) {throw error} method in the addProduct function
const errorMessage =
'Experiencing network difficulties. Please try again';
_errorDialog(message: errorMessage);
//call the error dialog method
//display in the message whatever defined message to display according to the API error response
}
setState(() {
_isLoading = false;
});
}
I was not returning anything in the signIn, signUp future methods. I needed to return the _authenticate method:
//AUTHENTICATION CREATE API call - Register user
Future<void> signup(String email, String password) async {
return _authenticate(
email: email,
password: password,
urlSegment: 'signUp',
);
}
//AUTHENTICATION READ API call - user sign in
Future<void> signin(String email, String password) async {
return _authenticate(
email: email,
password: password,
urlSegment: 'signInWithPassword',
);
}

Flutter - try and catch dont't handle firebase_auth errors

I have a problem handling firebase_auth errors, every way when I try signIn, I get some errors,
although I have used try and catch.
Earlier I have turned off the uncaught exceptions option in vsc but I would like to also get the error message from catch
sample errors message
Future<Either<LoginFailure, LoginSucces>> signInWithEmail(
{String email, String password}) async {
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} on PlatformException catch (e) {
return Left(LoginFailure(errorMessage: '${e.toString()}'));
}
}
In your log, you see the type of the uncaught exception is PlatformException, but it is not the type of the original exception throwed by signInWithEmailAndPassword(); it is instead used by the flutter framework, when it intercept the exception1, to wrap it. So if you want to catch only the exceptions thrown by signInWithEmailAndPassword(), check their exact type first, consulting the doc (if it explicit) or with a try/catch without on clause, like the following:
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} catch (e, stack) {
print("Catched exception: $e");
//if the exception log not shows the type (it is rare), you can log the exact type with:
print(e.runtimeType);
}
When you know the correct type of the exceptions that you want to catch, then you use the on clause:
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} on FirebaseError catch (e, stack) {
print(e);
//exceptions with a type other than FirebaseError are not caught here
}
Note FirebaseError is the type thrown using my package, firebase (others exist too, like firebase_auth); if you use a different package, check for yourself which exceptions you need to catch.
1 Flutter has its own mechanism for catching exceptions, which are therefore not really 'uncaught'; see for example this doc on error in flutter)
This code only catch PlatformException as written.
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} on PlatformException catch (e) {
return Left(LoginFailure(errorMessage: '${e.toString()}'));
}
you can catch all exception like this.
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} catch (e) {
return Left(LoginFailure(errorMessage: '${e.toString()}'));
}
also you can do this
try {
await _auth.signInWithEmailAndPassword(email: email, password: password);
} on PlatformException catch (e) {
return Left(LoginFailure(errorMessage: '${e.toString()}'));
} catch(e) {
// All other than Platform exception will drop here
print(e);
}

How to Handle Firebase Auth exceptions on flutter

Please does anyone know how to catch firebase Auth exceptions on flutter and display them?
Note: I am not interested in the console (catcherror((e) print(e))
I need something that is more effective, e.g " user doesn't exist" So that I can then pass it to a string and display it.
Been dealing with this for months.
Thanks in advance.
I have tried replacing print(e) with // errorMessage=e.toString(); and then passing it to a function, all efforts have been futile.
FirebaseAuth.instance
.signInWithEmailAndPassword(email: emailController.text, password: passwordController.text)
.then((FirebaseUser user) {
_isInAsyncCall=false;
Navigator.of(context).pushReplacementNamed("/TheNextPage");
}).catchError((e) {
// errorMessage=e.toString();
print(e);
_showDialog(errorMessage);
//exceptionNotice();
//print(e);
I want to be able to extract the exception message and pass the exception message to a dialog that I can then display to the user.
NEW ANSWER (18/09/2020)
If you are using firebase_auth: ^0.18.0, error codes have changed!
For instance: ERROR_USER_NOT_FOUND is now user-not-found
I could not find any documentation about that, so I went into the source code and read comments for every error codes. (firebase_auth.dart)
I don't use all error codes in my app (e.g verification, password reset...) but you will find the most common ones in this code snippet:
(It handles old and new error codes)
String getMessageFromErrorCode() {
switch (this.errorCode) {
case "ERROR_EMAIL_ALREADY_IN_USE":
case "account-exists-with-different-credential":
case "email-already-in-use":
return "Email already used. Go to login page.";
break;
case "ERROR_WRONG_PASSWORD":
case "wrong-password":
return "Wrong email/password combination.";
break;
case "ERROR_USER_NOT_FOUND":
case "user-not-found":
return "No user found with this email.";
break;
case "ERROR_USER_DISABLED":
case "user-disabled":
return "User disabled.";
break;
case "ERROR_TOO_MANY_REQUESTS":
case "operation-not-allowed":
return "Too many requests to log into this account.";
break;
case "ERROR_OPERATION_NOT_ALLOWED":
case "operation-not-allowed":
return "Server error, please try again later.";
break;
case "ERROR_INVALID_EMAIL":
case "invalid-email":
return "Email address is invalid.";
break;
default:
return "Login failed. Please try again.";
break;
}
}
If you are using firebase_auth: ^0.18.0, error codes have changed! Check the next answer.
I just coded myself a way to do this without Platform dependent Code:
This is possible since .signInWithEmailAndPassword correctly throws Errors with defined codes, that we can grab to identify the error and handle things in the way the should be handled.
The following example creates a new Future.error, if any error happens, and a Bloc is then configured to shovel that data through to the Widget.
Future<String> signIn(String email, String password) async {
FirebaseUser user;
String errorMessage;
try {
AuthResult result = await _firebaseAuth.signInWithEmailAndPassword(email: email, password: password);
user = result.user;
} catch (error) {
switch (error.code) {
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 user.uid;
}
(21/02/20) EDIT: This answer is old and the other answers contains cross platform solutions so you should look at theirs first and treat this as a fallback solution.
The firebase auth plugin doesn't really have a proper cross-platform error code system yet so you have to handle errors for android and ios independently.
I'm currently using the temporary fix from this github issue: #20223
Do note since its a temp fix, don't expect it to be fully reliable as a permanent solution.
enum authProblems { UserNotFound, PasswordNotValid, NetworkError }
try {
FirebaseUser user = await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email,
password: password,
);
} catch (e) {
authProblems errorType;
if (Platform.isAndroid) {
switch (e.message) {
case 'There is no user record corresponding to this identifier. The user may have been deleted.':
errorType = authProblems.UserNotFound;
break;
case 'The password is invalid or the user does not have a password.':
errorType = authProblems.PasswordNotValid;
break;
case 'A network error (such as timeout, interrupted connection or unreachable host) has occurred.':
errorType = authProblems.NetworkError;
break;
// ...
default:
print('Case ${e.message} is not yet implemented');
}
} else if (Platform.isIOS) {
switch (e.code) {
case 'Error 17011':
errorType = authProblems.UserNotFound;
break;
case 'Error 17009':
errorType = authProblems.PasswordNotValid;
break;
case 'Error 17020':
errorType = authProblems.NetworkError;
break;
// ...
default:
print('Case ${e.message} is not yet implemented');
}
}
print('The error is $errorType');
}
Expanding on the accepted answer I thought it's worth to mention that:
The firebase_auth plugin has AuthException.
As pointed out in this Github issue post you can have the same error codes for Android and iOS.
If you have this code in a non-UI layer you can use rethrow or better throw your own formatted exceptions and catch those at the UI level (where you'll know exactly the kind of error you'll get).
try {
AuthResult authResult = await FirebaseAuth.instance.signInWithCredential(credential);
// Your auth logic ...
} on AuthException catch (e) {
print('''
caught firebase auth exception\n
${e.code}\n
${e.message}
''');
var message = 'Oops!'; // Default message
switch (e.code) {
case 'ERROR_WRONG_PASSWORD':
message = 'The password you entered is totally wrong!';
break;
// More custom messages ...
}
throw Exception(message); // Or extend this with a custom exception class
} catch (e) {
print('''
caught exception\n
$e
''');
rethrow;
}
the exceptions can be handled using, FirebaseAuthException class.
Here's the code for login using email and password:
void loginUser(String email, String password) async {
try {
await _auth.signInWithEmailAndPassword(email: email, password:password);
} on FirebaseAuthException catch (e) {
// Your logic for Firebase related exceptions
} catch (e) {
// your logic for other exceptions!
}
You can use your own logic to handle the error, e.g show a alert dialog, etc.
Same can be done for creating a user.
in Auth Class have this function:
Future signUpWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
FirebaseUser user = result.user;
return user;
} catch (e) {
return e;
}
}
The catch error above returns a runTimeType of PlatformException and a PlatformException in flutter has 3 properties check here!
in your Dart file, implement this on button listeners:
String error = "";
dynamic result = await _auth.signUpWithEmailAndPassword(email, password);
if (result.runtimeType == PlatformException) {
if (result.message != null) {
setState(() {
error = result.message;
});
} else {
setState(() {
error = "Unknown Error";
});
}
}
So I faced this issue today and instead of hardcoding the error messages to display, I decided to use string manipulations and I managed to get the message.
The goal was to get the message (everything after ]).
Example: get this => Password should be at least 6 characters from this => [firebase_auth/weak-password] Password should be at least 6 characters.
So using the exception from the try-catch, I converted it to string first, then replaced the first 14 characters (from '[' to '/') with nothing, so I was left with weak-password] Password should be at least 6 characters.
Then the split function with ']' pattern to search the remaining string for the ']' symbol and split the whole string into two with the index of the ']' symbol as the pivot. This returns a list with two Strings; 'weak-password' and 'Password should be at least 6 characters'. Use the index 1 to get the second string which is the error message.
e.toString().replaceRange(0, 14, '').split(']')[1]
I manage the firebase auth exception with the exceptions codes of the version
firebase_auth: ^3.3.6
firebase_core: ^1.12.0
This is the code that work for me:
Future<void> loginWithEmailAndPassword({
required String email,
required String password,
}) async {
try {
await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
} on firebase_auth.FirebaseAuthException catch (e) {
switch (e.code) {
case "invalid-email":
//Thrown if the email address is not valid.
throw InvalidEmailException();
case "user-disabled":
//Thrown if the user corresponding to the given email has been disabled.
throw UserDisabledException();
case "user-not-found":
//Thrown if there is no user corresponding to the given email.
throw UserNotFoundException();
case "wrong-password":
throw PasswordExceptions();
//Thrown if the password is invalid for the given email, or the account corresponding to the email does not have a password set.
default:
throw UncknownAuthException();
}
}
}
And I create the exceptions to control the messeges to display in the UI later like this:
class AuthenticationException implements Exception {}
class InvalidEmailException extends AuthenticationException {}
class PasswordExceptions extends AuthenticationException {}
class UserNotFoundException extends AuthenticationException {}
class UserDisabledException extends AuthenticationException {}
class UncknownAuthException extends AuthenticationException {}
Hope it help to someone having problems to handle auth exceptions!
in Dart you can react to different Exceptions using the on syntax. Since Firebase uses its own PlatformException you can easily catch them with:
try {
AuthResult result = await signUp(email, password);
} on PlatformException catch (e) {
print(e.message);
} on Exception catch (e) {
print(e);
}
PlatformException brings a code as well as a message which can be displayed in the UI, i.e. :
PlatformException(ERROR_EMAIL_ALREADY_IN_USE, The email address is already in use by another account., null)
I was stuck on this for a while too, i created this gist with all the available errors here with an example, covers all the platform exception codes
Example for handling sign up exceptions
Future<String> signUp(String email, String password, String firstName) async {
FirebaseUser user;
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
user = result.user;
name = user.displayName;
email = user.email;
Firestore.instance.collection('users').document(user.uid).setData({
"uid": user.uid,
"firstName": firstName,
"email": email,
"userImage": userImage,
});
} catch (error) {
switch (error.code) {
case "ERROR_OPERATION_NOT_ALLOWED":
errorMessage = "Anonymous accounts are not enabled";
break;
case "ERROR_WEAK_PASSWORD":
errorMessage = "Your password is too weak";
break;
case "ERROR_INVALID_EMAIL":
errorMessage = "Your email is invalid";
break;
case "ERROR_EMAIL_ALREADY_IN_USE":
errorMessage = "Email is already in use on different account";
break;
case "ERROR_INVALID_CREDENTIAL":
errorMessage = "Your email is invalid";
break;
default:
errorMessage = "An undefined Error happened.";
}
}
if (errorMessage != null) {
return Future.error(errorMessage);
}
return user.uid;
}
Example for handling sign in exceptions
Future<String> signIn(String email, String password) async {
FirebaseUser user;
try {
AuthResult result = await _auth.signInWithEmailAndPassword(
email: email, password: password);
user = result.user;
name = user.displayName;
email = user.email;
userId = user.uid;
} catch (error) {
switch (error.code) {
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 user.uid;
}
I prefer to create api layer response and error models and wrap the firebase plugin error and response objects in them. For sign in with email and password i have this
#override
Future<dynamic> loginWithEmailAndPassword(String email, String password) async {
try {
await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
return FirebaseSignInWithEmailResponse();
} catch (exception) {
return _mapLoginWithEmailError(exception);
}
}
ApiError _mapLoginWithEmailError(PlatformException error) {
final code = error.code;
if (code == 'ERROR_INVALID_EMAIL') {
return FirebaseSignInWithEmailError(
message: 'Your email is not valid. Please enter a valid email',
type: FirebaseSignInWithEmailErrorType.INVALID_EMAIL);
} else if (code == 'ERROR_WRONG_PASSWORD') {
return FirebaseSignInWithEmailError(
message: 'Your password is incorrect',
type: FirebaseSignInWithEmailErrorType.WRONG_PASSWORD);
} else if (code == 'ERROR_USER_NOT_FOUND') {
return FirebaseSignInWithEmailError(
message: 'You do not have an account. Please Sign Up to'
'proceed',
type: FirebaseSignInWithEmailErrorType.USER_NOT_FOUND);
} else if (code == 'ERROR_TOO_MANY_REQUESTS') {
return FirebaseSignInWithEmailError(
message: 'Did you forget your credentials? Reset your password',
type: FirebaseSignInWithEmailErrorType.TOO_MANY_REQUESTS);
} else if (code == 'ERROR_USER_DISABLED') {
return FirebaseSignInWithEmailError(
message: 'Your account has been disabled. Please contact support',
type: FirebaseSignInWithEmailErrorType.USER_DISABLED);
} else if (code == 'ERROR_OPERATION_NOT_ALLOWED') {
throw 'Email and Password accounts are disabled. Enable them in the '
'firebase console?';
} else {
return FirebaseSignInWithEmailError(
message: 'Make sure you have a stable connection and try again'
type: FirebaseSignInWithEmailErrorType.CONNECTIVITY);
}
}
I never return the AuthResult from firebase. Instead i listen to the onAuthStateChanged stream and react accordingly if there is a change.
I have the same error of "firebse platform exeption:" in flutter using "Firebase auth"
and it didn't resolve even using try catch and trim() method in passing arrguments.
The problem is when you run app using Button "Run" in main.dart it won't callback and catch the error.
Solution: In Vscode terminal type "Flutter run" (for debug mode). or "Flutter run --release" (for release mode) now you won't face platform exception.
I had an issue where I didn't want the "com.google.firebase.FirebaseException: An internal error has occurred. [ Unable to resolve host "www.googleapis.com":No address associated
with hostname ]" which would indicate to a user that the backend being used is firebase. Thus, I just used toString().replaceAll()
Future<void> signIn() async {
final formState = _formkey.currentState;
var _date = DateTime.now();
if (formState!.validate()) {
emailFocus!.unfocus();
passwordFocus!.unfocus();
formState.save();
setState(() {
isloading = true;
_errorMessage = '';
});
try {
UserCredential user = await _firebaseAuth.signInWithEmailAndPassword(
email: _email, password: _password!);
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('email', _email);
await FirebaseFirestore.instance
.collection('Users Token Data')
.doc(user.user!.uid)
.set({'Email': _email, 'Token': _token, 'Date': _date});
Navigator.pushNamedAndRemoveUntil(
context, RouteNames.homePage, (e) => false);
} on FirebaseAuthException catch (e) {
setState(() {
isloading = false;
_errorMessage = e.message.toString().replaceAll(
'com.google.firebase.FirebaseException: An internal error has' +
' occurred. [ Unable to resolve host "www.googleapis.com":' +
"No address associated with hostname ]",
"Please Check Network Connection");
});
print(e.message);
}
}
}
}
Just incase if you don't wanna reveal too much information from the error message.
I have also recently faced this error and, I have found out that the .catchError() callback wasn't being called in the debug mode (which is when you click the Run->Start Debugging button in VSCode).
However, when you type in flutter run -d , then, the .catchError() method gets called back as it is not in debug mode.
To get your preferred simulator's code paste this line of code in the terminal:
instruments -s devices
If that doesn't work, you can also try pasting this:
xcrun simctl list
The ```.catchError()`` method will get called unlike before and the code inside that will get executed as expected!
Additionally, the app won't crash anymore with a PlatformException() and instead you will get a log like this one:
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: The getter 'uid' was called on null.
Receiver: null
I have been facing this problem in Google Sign In too, in which the .catchError() was not being called!
In conclusion, if you have some error with handling errors in Firebase Authentication, you should first try to first run in through the terminal. Thanks, and I hope this helps!
try this , i had the same proplem and this code worked with me
catch (e) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Wrong UserName or Password')));
}
Firebase-Auth Latest version provides a simple way to get error code and error Messages using the following try catch statements:
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: "name#example.com",
password: "SuperSecretPassword!"
);
} on FirebaseAuthException catch (e) {
print('Failed with error code: ${e.code}');
print(e.message);
}
Source:
Firebase Documentation
This code will show a red snack bar that contains the exception cause like "User already in use by other account".
auth.createUserWithEmailAndPassword(
email: email,
password: password,
).onError((error,stackTrace){
if(error.runtimeType == FirebaseAuthException) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(error.toString().replaceRange(0, 14, '').split(']')[1]),
backgroundColor: Theme.of(context).colorScheme.error,
),
);
}
}
try {
final newuser = await _auth.createUserWithEmailAndPassword(
email: emailController.text, password: passwordController.text);
// print("Done");
} catch (e) {
print(e);
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(e.message),
actions: <Widget>[
FlatButton(
child: new Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}

Resources