Using Firebase, how do I catch a specific exception and tell the user gracefully about it? E.g :
FirebaseAuthInvalidCredentialsException: The email address is badly
formatted.
I'm using the code below to signup the user using email and password, but I'm not that advanced in java.
mAuth.createUserWithEmailAndPassword(email, pwd)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) {
//H.toast(c, task.getException().getMessage());
Log.e("Signup Error", "onCancelled", task.getException());
} else {
FirebaseUser user = mAuth.getCurrentUser();
String uid = user.getUid();
}
}
});
You can throw the Exception returned by task.getException inside a try block and catch each type of Exception that may be thrown by the method you are using.
Here is an example from the OnCompleteListener for the createUserWithEmailAndPassword method.
if(!task.isSuccessful()) {
try {
throw task.getException();
} catch(FirebaseAuthWeakPasswordException e) {
mTxtPassword.setError(getString(R.string.error_weak_password));
mTxtPassword.requestFocus();
} catch(FirebaseAuthInvalidCredentialsException e) {
mTxtEmail.setError(getString(R.string.error_invalid_email));
mTxtEmail.requestFocus();
} catch(FirebaseAuthUserCollisionException e) {
mTxtEmail.setError(getString(R.string.error_user_exists));
mTxtEmail.requestFocus();
} catch(Exception e) {
Log.e(TAG, e.getMessage());
}
}
In addition to #pdegand59 answer, I found some error code in Firebase library and test on Android (the returned error code). Hope this helps, Regards.
("ERROR_INVALID_CUSTOM_TOKEN", "The custom token format is incorrect. Please check the documentation."));
("ERROR_CUSTOM_TOKEN_MISMATCH", "The custom token corresponds to a different audience."));
("ERROR_INVALID_CREDENTIAL", "The supplied auth credential is malformed or has expired."));
("ERROR_INVALID_EMAIL", "The email address is badly formatted."));
("ERROR_WRONG_PASSWORD", "The password is invalid or the user does not have a password."));
("ERROR_USER_MISMATCH", "The supplied credentials do not correspond to the previously signed in user."));
("ERROR_REQUIRES_RECENT_LOGIN", "This operation is sensitive and requires recent authentication. Log in again before retrying this request."));
("ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL", "An account already exists with the same email address but different sign-in credentials. Sign in using a provider associated with this email address."));
("ERROR_EMAIL_ALREADY_IN_USE", "The email address is already in use by another account."));
("ERROR_CREDENTIAL_ALREADY_IN_USE", "This credential is already associated with a different user account."));
("ERROR_USER_DISABLED", "The user account has been disabled by an administrator."));
("ERROR_USER_TOKEN_EXPIRED", "The user\'s credential is no longer valid. The user must sign in again."));
("ERROR_USER_NOT_FOUND", "There is no user record corresponding to this identifier. The user may have been deleted."));
("ERROR_INVALID_USER_TOKEN", "The user\'s credential is no longer valid. The user must sign in again."));
("ERROR_OPERATION_NOT_ALLOWED", "This operation is not allowed. You must enable this service in the console."));
("ERROR_WEAK_PASSWORD", "The given password is invalid."));
("ERROR_MISSING_EMAIL", "An email address must be provided.";
There are a number of exceptions associated with firebase auth.
In addition to #kingspeech
You should use ((FirebaseAuthException)task.getException()).getErrorCode() to get the type of error and then handle it in switch like this :
private void loginUser(String email, String password) {
mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
startActivity(new Intent(MainActivity.this, Main2Activity.class));
} else {
String errorCode = ((FirebaseAuthException) task.getException()).getErrorCode();
switch (errorCode) {
case "ERROR_INVALID_CUSTOM_TOKEN":
Toast.makeText(MainActivity.this, "The custom token format is incorrect. Please check the documentation.", Toast.LENGTH_LONG).show();
break;
case "ERROR_CUSTOM_TOKEN_MISMATCH":
Toast.makeText(MainActivity.this, "The custom token corresponds to a different audience.", Toast.LENGTH_LONG).show();
break;
case "ERROR_INVALID_CREDENTIAL":
Toast.makeText(MainActivity.this, "The supplied auth credential is malformed or has expired.", Toast.LENGTH_LONG).show();
break;
case "ERROR_INVALID_EMAIL":
Toast.makeText(MainActivity.this, "The email address is badly formatted.", Toast.LENGTH_LONG).show();
etEmail.setError("The email address is badly formatted.");
etEmail.requestFocus();
break;
case "ERROR_WRONG_PASSWORD":
Toast.makeText(MainActivity.this, "The password is invalid or the user does not have a password.", Toast.LENGTH_LONG).show();
etPassword.setError("password is incorrect ");
etPassword.requestFocus();
etPassword.setText("");
break;
case "ERROR_USER_MISMATCH":
Toast.makeText(MainActivity.this, "The supplied credentials do not correspond to the previously signed in user.", Toast.LENGTH_LONG).show();
break;
case "ERROR_REQUIRES_RECENT_LOGIN":
Toast.makeText(MainActivity.this, "This operation is sensitive and requires recent authentication. Log in again before retrying this request.", Toast.LENGTH_LONG).show();
break;
case "ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL":
Toast.makeText(MainActivity.this, "An account already exists with the same email address but different sign-in credentials. Sign in using a provider associated with this email address.", Toast.LENGTH_LONG).show();
break;
case "ERROR_EMAIL_ALREADY_IN_USE":
Toast.makeText(MainActivity.this, "The email address is already in use by another account. ", Toast.LENGTH_LONG).show();
etEmail.setError("The email address is already in use by another account.");
etEmail.requestFocus();
break;
case "ERROR_CREDENTIAL_ALREADY_IN_USE":
Toast.makeText(MainActivity.this, "This credential is already associated with a different user account.", Toast.LENGTH_LONG).show();
break;
case "ERROR_USER_DISABLED":
Toast.makeText(MainActivity.this, "The user account has been disabled by an administrator.", Toast.LENGTH_LONG).show();
break;
case "ERROR_USER_TOKEN_EXPIRED":
Toast.makeText(MainActivity.this, "The user\\'s credential is no longer valid. The user must sign in again.", Toast.LENGTH_LONG).show();
break;
case "ERROR_USER_NOT_FOUND":
Toast.makeText(MainActivity.this, "There is no user record corresponding to this identifier. The user may have been deleted.", Toast.LENGTH_LONG).show();
break;
case "ERROR_INVALID_USER_TOKEN":
Toast.makeText(MainActivity.this, "The user\\'s credential is no longer valid. The user must sign in again.", Toast.LENGTH_LONG).show();
break;
case "ERROR_OPERATION_NOT_ALLOWED":
Toast.makeText(MainActivity.this, "This operation is not allowed. You must enable this service in the console.", Toast.LENGTH_LONG).show();
break;
case "ERROR_WEAK_PASSWORD":
Toast.makeText(MainActivity.this, "The given password is invalid.", Toast.LENGTH_LONG).show();
etPassword.setError("The password is invalid it must 6 characters at least");
etPassword.requestFocus();
break;
}
}
}
});
}
You should use ((FirebaseAuthException)task.getException()).getErrorCode() to get the type of error and fail gracefully if this is the error code for a bad formatted email.
Unfortunately, I couldn't find the list of error codes used by Firebase.
Trigger the exception once, note the error code and code accordingly.
Solution using Kotlin
fun signInWithEmail(email: String, passKey: String) {
FirebaseAuth.getInstance().signInWithEmailAndPassword(email, passKey).addOnSuccessListener {
it.user?.let {
authResultOperation.postValue(AuthResultOperation.OnSuccessSignIn)
}
}.addOnFailureListener {
val errorCode = (it.exception as FirebaseAuthException).errorCode
val errorMessage = authErrors[errorCode] ?: R.string.error_login_default_error
Toast.makeText(context, context.getString(errorMessage),Toast.LENGTH_LONG).show()
}
}
Explanation: Basically It's just a map that match firebase error codes with a custom string resource.
val authErrors = mapOf("ERROR_INVALID_CUSTOM_TOKEN" to R.string.error_login_custom_token,
"ERROR_CUSTOM_TOKEN_MISMATCH" to R.string.error_login_custom_token_mismatch,
"ERROR_INVALID_CREDENTIAL" to R.string.error_login_credential_malformed_or_expired,
"ERROR_INVALID_EMAIL" to R.string.error_login_invalid_email,
"ERROR_WRONG_PASSWORD" to R.string.error_login_wrong_password,
"ERROR_USER_MISMATCH" to R.string.error_login_user_mismatch,
"ERROR_REQUIRES_RECENT_LOGIN" to R.string.error_login_requires_recent_login,
"ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL" to R.string.error_login_accounts_exits_with_different_credential,
"ERROR_EMAIL_ALREADY_IN_USE" to R.string.error_login_email_already_in_use,
"ERROR_CREDENTIAL_ALREADY_IN_USE" to R.string.error_login_credential_already_in_use,
"ERROR_USER_DISABLED" to R.string.error_login_user_disabled,
"ERROR_USER_TOKEN_EXPIRED" to R.string.error_login_user_token_expired,
"ERROR_USER_NOT_FOUND" to R.string.error_login_user_not_found,
"ERROR_INVALID_USER_TOKEN" to R.string.error_login_invalid_user_token,
"ERROR_OPERATION_NOT_ALLOWED" to R.string.error_login_operation_not_allowed,
"ERROR_WEAK_PASSWORD" to R.string.error_login_password_is_weak)
String resources (Feel free to change it according to your requirements)
<resources>
<string name="error_login_custom_token">The custom token format is incorrect. Please check the documentation.</string>
<string name="error_login_custom_token_mismatch">The custom token corresponds to a different audience.</string>
<string name="error_login_credential_malformed_or_expired">The supplied auth credential is malformed or has expired.</string>
<string name="error_login_invalid_email">The email address is badly formatted.</string>
<string name="error_login_wrong_password">The password is invalid or the user does not have a password.</string>
<string name="error_login_user_mismatch">The supplied credentials do not correspond to the previously signed in user.</string>
<string name="error_login_requires_recent_login">This operation is sensitive and requires recent authentication. Log in again before retrying this request.</string>
<string name="error_login_accounts_exits_with_different_credential">An account already exists with the same email address but different sign-in credentials. Sign in using a provider associated with this email address.</string>
<string name="error_login_email_already_in_use">The email address is already in use by another account.</string>
<string name="error_login_credential_already_in_use">This credential is already associated with a different user account.</string>
<string name="error_login_user_disabled">The user account has been disabled by an administrator.</string>
<string name="error_login_user_not_found">There is no user record corresponding to this identifier. The user may have been deleted.</string>
<string name="error_login_operation_not_allowed">This operation is not allowed. You must enable this service in the console.</string>
<string name="error_login_password_is_weak">The given password is invalid.</string>
<string name="error_login_user_token_expired">The user\'s credential is no longer valid. The user must sign in again</string>
<string name="error_login_invalid_user_token">The user\'s credential is no longer valid. The user must sign in again.</string>
</resources>
If you simply want display a message to the user this works. Simple and Elegant:
if (!task.isSuccessful()) {
Log.w(TAG, "signInWithEmail:failed", task.getException());
Toast.makeText(LoginActivity.this, "User Authentication Failed: " + task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
It appears that the .getMessage() method converts the exception to a usable format for us already and all we have to do is display that somewhere to the user.
(This is my first comment, constructive criticism please)
You can use either steve-guidetti or pdegand59 method. I used steve-guidetti's method(Two exceptions are missing)
For all possible exception please find below ref.
It is well documented here.
https://firebase.google.com/docs/reference/js/firebase.auth.Auth
Search for "createUserWithEmailAndPassword" and find the
Error Codes
auth/email-already-in-use
Thrown if there already exists an account with the given email address.
auth/invalid-email
Thrown if the email address is not valid.
auth/operation-not-allowed
Thrown if email/password accounts are not enabled. Enable email/password accounts in the Firebase Console, under the Auth tab.
auth/weak-password
Thrown if the password is not strong enough.
For all five exceptions: Check here
https://firebase.google.com/docs/reference/android/com/google/firebase/auth/FirebaseAuthException
Here you can find 5 different types of AuthException. 4 Known Direct subclass and 1 indirect subclass
You can use either steve-guidetti or pdegand59 method.
If you are sending upstream messages from user to cloud, implement firebase callback functions onMessageSent and onSendError to check the status of upstream messages. In error cases, onSendError returns a SendException with an error code.
For example, if the client attempts to send more messages after the 20-message limit is reached, it returns SendException#ERROR_TOO_MANY_MESSAGES.
To catch a firebase Exception is easy, you should add .addOnFailureListener after you add .addOnCompleteListener like this:
private void login_user(String email, String password) {
mAuth.signInWithEmailAndPassword(email,password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
Intent intent = new Intent(getApplicationContext(),MainActivity.class);
startActivity(intent);
finish();
}if(!task.isSuccessful()){
// To know The Excepton
//Toast.makeText(LoginActivity.this, ""+task.getException(), Toast.LENGTH_LONG).show();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
if( e instanceof FirebaseAuthInvalidUserException){
Toast.makeText(LoginActivity.this, "This User Not Found , Create A New Account", Toast.LENGTH_SHORT).show();
}
if( e instanceof FirebaseAuthInvalidCredentialsException){
Toast.makeText(LoginActivity.this, "The Password Is Invalid, Please Try Valid Password", Toast.LENGTH_SHORT).show();
}
if(e instanceof FirebaseNetworkException){
Toast.makeText(LoginActivity.this, "Please Check Your Connection", Toast.LENGTH_SHORT).show();
}
}
});
I tried another solutions but didn't like them.
What about this:
if (!task.isSuccessful()) {
Exception exc = task.getException();
if (exc.getMessage().contains("The email address is badly formatted.")) {
etUser.setError(getString(R.string.error_wrong_email));
etUser.requestFocus();
}
else
if (exc.getMessage().contains("There is no user record corresponding to this identifier. The user may have been deleted.")) {
etUser.setError(getString(R.string.error_user_not_exist));
etUser.requestFocus();
}
else
if (exc.getMessage().contains("The password is invalid or the user does not have a password")) {
etPass.setError(getString(R.string.error_wrong_password));
etPass.requestFocus();
}
Log.w(TAG, "signInWithEmail:failed", task.getException());
Toast.makeText(AuthActivity.this, R.string.auth_failed,
Toast.LENGTH_SHORT).show();
}
LOGIN_EXCEPTIONS
FirebaseAuthException - Generic exception related to Firebase Authentication. Check the error code and message for more details.
ERROR_USER_DISABLED if the user has been disabled (for example, in the Firebase console)
ERROR_USER_NOT_FOUND if the user has been deleted (for example, in the Firebase console, or in another instance of this app)
ERROR_USER_TOKEN_EXPIRED if the user's token has been revoked in the backend. This happens automatically if the user's credentials change in another device (for example, on a password change event).
ERROR_INVALID_USER_TOKEN if the user's token is malformed. This should not happen under normal circumstances.
mAuth.signInWithEmailAndPassword(login, pass)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful())
{
}else if (task.getException() instanceof FirebaseAuthInvalidUserException) {
}else if(((FirebaseAuthException) task.getException()).getErrorCode().equals("ERROR_USER_DISABLED"))
{
}else if(((FirebaseAuthException) task.getException()).getErrorCode().equals("ERROR_USER_NOT_FOUND "))
{
}else if(((FirebaseAuthException) task.getException()).getErrorCode().equals("ERROR_USER_TOKEN_EXPIRED "))
{
}else if(((FirebaseAuthException) task.getException()).getErrorCode().equals("ERROR_INVALID_USER_TOKEN "))
{
}
}
});
REGISTER_EXCEPTIONS
FirebaseAuthEmailException
Represents the exception which is a result of an attempt to send an email via Firebase Auth (e.g. a password reset email)
FirebaseAuthInvalidCredentialsException - Thrown when one or more of the credentials passed to a method fail to identify and/or authenticate the user subject of that operation. Inspect the error code and message to find out the specific cause.
FirebaseAuthWeakPasswordException - Thrown when using a weak password (less than 6 chars) to create a new account or to update an existing account's password. Use getReason() to get a message with the reason the validation failed that you can display to your users.
According to me the default message is informative enough. So I used it rather than any custom message and it worked pretty well for me.
if (!task.isSuccessful())
{
// there was an error
String yourString = task.getException().toString();
String target = "Exception:";
String error = yourString.substring(yourString.indexOf(target) + target.length() + 1, yourString.length());
Toast.makeText(LoginScreen.this, "Error: "+error, Toast.LENGTH_LONG).show();
}
p.s. this is my first answer on stack overflow. Do let me know if it was helpful.
try {
throw task.getException();
} catch(FirebaseAuthException e) {
switch (e.getErrorCode()){
case "ERROR_WEAK_PASSWORD":
Toast.makeText(this, "The given password is invalid.", Toast.LENGTH_SHORT).show();
break;
//and other
}
}
error codes: https://stackoverflow.com/a/38244409/2425851
In the past we used the getErrorCode() to get the type of error and fail gracefully. With the newer versions of the api, getErrorCode() is deprecated. We should use response.getError().getErrorCode() instead
com.firebase.ui.auth.IdpResponse
#Deprecated
public int getErrorCode()
Get the error code for a failed sign in
Deprecated use getError() instead
So for e.g.
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_SIGN_IN) {
IdpResponse response = IdpResponse.fromResultIntent(data);
// Successfully signed in
if (resultCode == RESULT_OK) {
//dbHandler = DBMS.getInstance(this);
FirebaseAuth auth = FirebaseAuth.getInstance();
FirebaseUser user = auth.getCurrentUser();
FirebaseUserMetadata metadata = auth.getCurrentUser().getMetadata();
// initialize profile first
if (metadata.getCreationTimestamp() == metadata.getLastSignInTimestamp()) {
//start main activity after profile setup
startActivity(new Intent(this, MainActivity.class));
return;
} else {
// This is an existing user
// show them a welcome back screen.
startActivity(new Intent(this, MainActivity.class));
return;
}
} else {
// Sign in failed
// check response for error code
if (response == null) {
// User pressed back button
showSnackbar(R.string.sign_in_cancelled);
return;
}
if (response.getError().getErrorCode() == ErrorCodes.NO_NETWORK) {
showSnackbar(R.string.no_internet_connection);
return;
}
if (response.getError().getErrorCode() == ErrorCodes.UNKNOWN_ERROR) {
showSnackbar(R.string.unknown_error);
return;
}
}
showSnackbar(R.string.unknown_sign_in_response);
}
}
Try the following:
if (task.isSuccessful()) {
//Toast.makeText(getContext(),"Registration successful", Toast.LENGTH_SHORT).show();
try {
Toast.makeText(getContext(),"Registration successful", Toast.LENGTH_SHORT).show();
throw task.getException();
}
// if user enters wrong email.
catch (FirebaseAuthWeakPasswordException weakPassword) {
Log.d("Registration Error", "onComplete: weak_password");
// TODO: take your actions!
}
// if user enters wrong password.
catch (FirebaseAuthInvalidCredentialsException malformedEmail) {
Log.d("Registration Error", "onComplete: malformed_email");
// TODO: Take your action
}
catch (FirebaseAuthUserCollisionException existEmail) {
Log.d("Registration Error", "onComplete: exist_email");
// TODO: Take your action
}
catch (Exception e) {
Log.d("Registration Error", "onComplete: " + e.getMessage());
}
} else {
//Toast.makeText(getContext(), "ERROR, Please try again.", Toast.LENGTH_SHORT).show();
Toast.makeText(getContext(), task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
There are too many Firebase Authentication exceptions to handle, and I'm not sure if handling all of them is a good thing due to a large amount of code to add (as you can see from other answers).
I just got a FirebaseTooManyRequestsException after Task<AuthResult.isSuccessful() returned false:
firebaseAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener {
if (it.isSuccessful) {
[...]
} else {
[FirebaseTooManyRequestsException and others that can be returned here]
}
}
com.google.firebase.FirebaseTooManyRequestsException: We have blocked all requests from this device due to unusual activity. Try again later. [ Access to this account has been temporarily disabled due to many failed login attempts. You can immediately restore it by resetting your password or you can try again later. ]
So, if you want to catch all of them or at least the ones that are more important to your logic, I hope that bringing another FirebaseAuth exception to this list helps you.
Here's a Kotlin parser that I use. it's adapted from FirebaseUI-Android
/**
* List of all possible results of [FirebaseAuthException.getErrorCode] and their meanings.
* TODO you can make description parameter private if you don't use it outside of this class
*/
enum class FirebaseAuthErrorParser(val description: String) {
ERROR_INVALID_CUSTOM_TOKEN("The custom token format is incorrect. Please check the documentation."),
ERROR_CUSTOM_TOKEN_MISMATCH("Invalid configuration. Ensure your app's SHA1 is correct in the Firebase console."),
ERROR_INVALID_CREDENTIAL("The supplied auth credential is malformed or has expired."),
ERROR_INVALID_EMAIL("The email address is badly formatted."),
ERROR_WRONG_PASSWORD("The password is invalid or the user does not have a password."),
ERROR_USER_MISMATCH("The supplied credentials do not correspond to the previously signed in user."),
ERROR_REQUIRES_RECENT_LOGIN("This operation is sensitive and requires recent authentication. Log in again before retrying this request."),
ERROR_ACCOUNT_EXISTS_WITH_DIFFERENT_CREDENTIAL("An account already exists with the same email address but different sign-in credentials. Sign in using a provider associated with this email address."),
ERROR_EMAIL_ALREADY_IN_USE("The email address is already in use by another account."),
ERROR_CREDENTIAL_ALREADY_IN_USE("This credential is already associated with a different user account."),
ERROR_USER_DISABLED("The user account has been disabled by an administrator."),
ERROR_USER_TOKEN_EXPIRED("The user's credential has expired. The user must sign in again."),
ERROR_USER_NOT_FOUND("There is no user record corresponding to this identifier. The user may have been deleted."),
ERROR_INVALID_USER_TOKEN("The user's credential is no longer valid. The user must sign in again."),
ERROR_OPERATION_NOT_ALLOWED("This operation is not allowed. Enable the sign-in method in the Authentication tab of the Firebase console"),
ERROR_TOO_MANY_REQUESTS("We have blocked all requests from this device due to unusual activity. Try again later."),
ERROR_WEAK_PASSWORD("The given password is too weak, please choose a stronger password."),
ERROR_EXPIRED_ACTION_CODE("The out of band code has expired."),
ERROR_INVALID_ACTION_CODE("The out of band code is invalid. This can happen if the code is malformed, expired, or has already been used."),
ERROR_INVALID_MESSAGE_PAYLOAD("The email template corresponding to this action contains invalid characters in its message. Please fix by going to the Auth email templates section in the Firebase Console."),
ERROR_INVALID_RECIPIENT_EMAIL("The email corresponding to this action failed to send as the provided recipient email address is invalid."),
ERROR_INVALID_SENDER("The email template corresponding to this action contains an invalid sender email or name. Please fix by going to the Auth email templates section in the Firebase Console."),
ERROR_MISSING_EMAIL("An email address must be provided."),
ERROR_MISSING_PASSWORD("A password must be provided."),
ERROR_MISSING_PHONE_NUMBER("To send verification codes, provide a phone number for the recipient."),
ERROR_INVALID_PHONE_NUMBER("The format of the phone number provided is incorrect. Please enter the phone number in a format that can be parsed into E.164 format. E.164 phone numbers are written in the format [+][country code][subscriber number including area code]."),
ERROR_MISSING_VERIFICATION_CODE("The phone auth credential was created with an empty sms verification code"),
ERROR_INVALID_VERIFICATION_CODE("The sms verification code used to create the phone auth credential is invalid. Please resend the verification code sms and be sure use the verification code provided by the user."),
ERROR_MISSING_VERIFICATION_ID("The phone auth credential was created with an empty verification ID"),
ERROR_INVALID_VERIFICATION_ID("The verification ID used to create the phone auth credential is invalid."),
ERROR_RETRY_PHONE_AUTH("An error occurred during authentication using the PhoneAuthCredential. Please retry authentication."),
ERROR_SESSION_EXPIRED("The sms code has expired. Please re-send the verification code to try again."),
ERROR_QUOTA_EXCEEDED("The sms quota for this project has been exceeded."),
ERROR_APP_NOT_AUTHORIZED("This app is not authorized to use Firebase Authentication. Please verify that the correct package name and SHA-1 are configured in the Firebase Console."),
ERROR_API_NOT_AVAILABLE("The API that you are calling is not available on devices without Google Play Services."),
ERROR_WEB_CONTEXT_CANCELED("The web operation was canceled by the user"),
ERROR_UNKNOWN("An unknown error occurred.");
companion object {
/**
* Get an [FirebaseAuthError.description] from an exception,
* returning [FirebaseAuthError.ERROR_UNKNOWN] as a default.
*/
fun fromException(ex: FirebaseAuthException): String {
return try {
valueOf(ex.errorCode).description
} catch (e: IllegalArgumentException) {
Log.e(TAG, e)
ERROR_UNKNOWN.description
}
}
}
}
This is how you use it:
val ErrorMsg = FirebaseAuthErrorParser.fromException(firebaseAuthEx)
you can use this:
mAuth.getCurrentUser().linkWithCredential(authCredential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Log.d(TAG, "linkWithCredential:success");
} else {
Log.w(TAG, "linkWithCredential:failure", task.getException());
Toast.makeText(getApplicationContext(), "Authentication failed. " + task.getException().toString, Toast.LENGTH_SHORT).show();
}
// ...
}
});
Related
This question already has answers here:
How to check "user email already exists" in firebase using Android Studio
(4 answers)
Closed 1 year ago.
I'm trying to create a logging activity for my app. So I used firebase. But now I want to make a toast that says when I insert an already existing email but I'm finding it difficult to do so. This is what I did:
public void checkEmailExistsOrNot(){
fAuth.fetchSignInMethodsForEmail(eml).addOnCompleteListener(new OnCompleteListener<SignInMethodQueryResult>() {
#Override
public void onComplete(#NonNull Task<SignInMethodQueryResult> task) {
if (task.getResult().getSignInMethods().size() == 0){
exist = false;
}else {
exist = true;
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
e.printStackTrace();
}
});
}
Here I check if the boolean is equal to true (therefore the email already exists and I do not continue with the registration) or if it is alse, the email does not exist, so I proceed with the registration:
checkEmailExistsOrNot();
if (exist) {
Toast.makeText(getApplicationContext(), "Email giĆ” registrata", Toast.LENGTH_SHORT);
return;
} else {
fAuth.createUserWithEmailAndPassword(eml, passw).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
progress.setVisibility(View.GONE);
if (task.isSuccessful()) {
Toast.makeText(getApplicationContext(), "registration made", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "registration not performed", Toast.LENGTH_SHORT).show();
}
}
});
}
The problem is that even when I insert already existing emails, the exist variable still remains false so the program tries to create an account, failing to do so, it brings up a toast that says registration not performed. How can I solve?
full code: https://codeshare.io/5QPeNL
Firebase automatically tells you if an email that you want to create an account with already exists.
When creating an account you should check if the task was succesfull and under
if(task.isSuccessful()) {} // you have this code in your last bit of code
else{} // you have this in your code already
(
you currently have the code
Toast.makeText(getApplicationContext(), "registration not performed", Toast.LENGTH_SHORT).show();
( it is pretty much the last line in the code you provided) but you should replace it with:
try {
throw task.getException();
} catch(FirebaseAuthUserCollisionException e) {
// email already in use
Toast.makeText(getApplicationContext(), "Email already taken!", Toast.LENGTH_SHORT).show();
}
So you do not need to check if an email exists yourself because Firebase will automatically throw an exception and then you can for example display a toast.
The problem here is that fetchSignInMethodsForEmail is asynchronous but you call it as if it is synchronouse. Turn your function into a Future / async call that returns true or false. Othervise your code continues without awaiting the onComplete so the value is always false.
I have account admin and another account want to reset password, with process like this,
User A reset password > send email to admin > admin reset password > admin send new password to user A (with email)> user A login with new password from Admin.. Can I do like this, tell me example source code java. Thanks
resetPass.setOnClickListener(view -> {
String userMail = resetEmail.getText().toString();
if (TextUtils.isEmpty(userMail)) {
Toast.makeText(ForgotPassActivity.this, "Please write your valid address first", Toast.LENGTH_SHORT).show();
}
else {
auth.sendPasswordResetEmail(userMail).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(ForgotPassActivity.this, "Please check your email account", Toast.LENGTH_SHORT).show();
startActivity(new Intent(ForgotPassActivity.this, Log_inActivity.class));
} else {
Toast.makeText(ForgotPassActivity.this, "Email not found, please try again.", Toast.LENGTH_SHORT).show();
}
}
});
}
});
Firebase Authentication only allows sending a password reset email to the currently signed in user. You can't send a password reset email to another user, as that would open the system up to abuse.
To implement the flow you describe, you'll need to implement your own email sending, and password reset. You can use the Firebase Admin SDK to handle the Firebase aspects of it (get the user, update password), but will need to find another system to send email, and implement your own verification code.
I want to check when a user attempts to signup with createUserWithEmailAndPassword() in Firebase user Authentication method, this user is already registered with my app.
To detect whether a user with that email address already exists, you can detect when the call to createUserWithEmailAndPassword () fails with auth/email-already-in-use. I see that #Srinivasan just posted an answer for this.
Alternatively, you can detect that an email address is already used by calling fetchSignInMethodsForEmail().
The usual flow for this is that you first ask the user to enter their email address, then call fetchSignInMethodsForEmail, and then move them to a screen that either asks for the rest of their registration details (if they're new), or show them the provider(s) with which they're signed up already.
When the user trying to create an user with same email address, the task response will be "Response: The email address is already in use by another account."
mFirebaseAuth.createUserWithEmailAndPassword(email,password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(task.isSuccessful()){
//User registered successfully
}else{
Log.i("Response","Failed to create user:"+task.getException().getMessage());
}
}
});
First of all, you need to make sure you have that restriction enabled in Firebase console (Account and email address settings). Take a look at #Srinivasan's answer.
Then, do this in your java code:
firebaseAuthenticator.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (!task.isSuccessful()) {
if (task.getException() instanceof FirebaseAuthUserCollisionException) {
Toast.makeText(SignUpActivity.this, "User with this email already exist.", Toast.LENGTH_SHORT).show();
}
} else {
sendVerificationEmail();
startActivity(new Intent(SignUpActivity.this, DetailsCaptureActivity.class));
}
// ...
}
});
This is where the trick happens:
if (task.getException() instanceof FirebaseAuthUserCollisionException) {
Toast.makeText(SignUpActivity.this,
"User with this email already exist.", Toast.LENGTH_SHORT).show();
Several exceptions can be thrown when registering a user with email and password, but the one we are interested in is the FirebaseAuthUserCollisionException. As the name implies, this exception is thrown if the email already exists. If the exception thrown is an instance of this class, let the user know.
As a practice of #Frank's answer here is the code of using fetchProvidersForEmail()
private boolean checkAccountEmailExistInFirebase(String email) {
FirebaseAuth mAuth = FirebaseAuth.getInstance();
final boolean[] b = new boolean[1];
mAuth.fetchProvidersForEmail(email).addOnCompleteListener(new OnCompleteListener<ProviderQueryResult>() {
#Override
public void onComplete(#NonNull Task<ProviderQueryResult> task) {
b[0] = !task.getResult().getProviders().isEmpty();
}
});
return b[0];
}
I was looking into this kind of condition where we can detect if user exists or not and perform registration and login. fetchProvidersForEmail is best option right now. I have found this tutorial. Hope it helps you too!
See : Manage Users
UserRecord userRecord = FirebaseAuth.getInstance().getUserByEmail(email);
System.out.println("Successfully fetched user data: " + userRecord.getEmail());
This method returns a UserRecord object for the user corresponding to the email provided.
If the provided email does not belong to an existing user or the user cannot be fetched for any other reason, the Admin SDK throws an error. For a full list of error codes, including descriptions and resolution steps, see Admin Authentication API Errors.
private ProgressDialog progressDialog;
progressDialog.setMessage("Registering, please Wait...");
progressDialog.show();
mAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
//checking if success
if (task.isSuccessful()) {
//Registration was successfull:
Toast.makeText(RegistrationActivity.this, "Successfully registered!", Toast.LENGTH_LONG).show();
} else {
//Registration failed:
//task.getException().getMessage() makes the magic
Toast.makeText(RegistrationActivity.this, "Registration failed! " + "\n" + task.getException().getMessage(), Toast.LENGTH_LONG).show();
}
progressDialog.dismiss();
}
});
Add below code to MainActivity.java file.When user attempt to register with the same email address a message "The email address is already used by another account" will pop up as a Toast
mAuth.createUserWithEmailAndPassword(email,password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if(!task.isSuccessful()){
Toast.makeText(MainActivity.this, task.getException().getMessage(), Toast.LENGTH_SHORT).show();
}
if(task.isSuccessful()){
Toast.makeText(MainActivity.this, "Sign up successfull", Toast.LENGTH_SHORT).show();
}
}
});
You do not have to do anything because the backend of Firebase will do the job.
Unless you are referring to reauthenticating of the app.
Take a scenario for an example, w
From the title, you would think that there is a published solution to my problem, but in fact I believe I read everything pertinent to my question, but nothing quite matched up. Here's what I've got:
First of all, this problem has never happened in my app before today, nor did my sign-in change in any way: same Google sign-in code, same account. Everything the same for the past three months, as long as I've been testing. And, as far as I can tell, the problem only occurs with a single account. When the user begins the sign-in process, they are presented with a choice of accounts to sign in with; in this case, I selected the first user:
Next, Google authenticates the user and we arrive here in the code:
So the question is, why did Firebase suddenly stop providing the display name (and the photo URL)? From the first screenshot, it's clear that the user has a specified name and photo. Apart from that, FirebaseAuth.getInstance().getCurrentUser().isAnonymous() is false, as expected. Any ideas on why this suddenly broke would be greatly appreciated!
I solved the problem by simply updating my name and photo URL using UserProfileChangeRequest() and the name and photo URL of my Google account, as suggested here:
private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
sendFirebaseEvent(FIREBASE_GOOGLE_AUTH_EVENT, FIREBASE_GOOGLE_AUTH_KEY, acct.getId());
// [START_EXCLUDE silent]
showProgressDialog();
googleAccount = acct;
// [END_EXCLUDE]
final AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
sendFirebaseEvent(FIREBASE_GOOGLE_AUTH_EVENT, FIREBASE_GOOGLE_AUTH_RESULT_KEY, "Success");
launchNextActivity();
} else {
// If sign in fails, display a message to the user.
sendFirebaseEvent(FIREBASE_GOOGLE_AUTH_EVENT, FIREBASE_GOOGLE_AUTH_RESULT_KEY, task.getException().getMessage());
Snackbar.make(findViewById(R.id.main_layout), "Authentication Failed.", Snackbar.LENGTH_SHORT).show();
updateUI(null);
}
// [START_EXCLUDE]
hideProgressDialog();
// [END_EXCLUDE]
}
});
}
private void launchNextActivity() {
mFirebaseAuth = FirebaseAuth.getInstance();
FirebaseUser mUser = mFirebaseAuth.getCurrentUser();
if (mUser.getDisplayName() == null || mUser.getDisplayName().length() == 0) {
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(googleAccount.getDisplayName())
.setPhotoUri(googleAccount.getPhotoUrl())
.build();
mUser.updateProfile(profileUpdates);
}
}
I have a firebase project which allows users to login only if they are already exists in identifier in authentication .
I already added few users using my web app with mobile numbers.
Now, in android I have used the signInWithPhoneAuthCredential method to get the users login.
But in this method, it allows any users to login even if the user is first time entering the mobile number.
Is there any method to restrict this ?
Sample Code :
private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = task.getResult().getUser();
// ...
} else {
// Sign in failed, display a message and update the UI
Log.w(TAG, "signInWithCredential:failure", task.getException());
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
// The verification code entered was invalid
}
}
}
});
}
According to the docs:
signInWithPhoneNumber:
Asynchronously signs in using a phone number. This method sends a code via SMS to the given phone number, and returns a firebase.auth.ConfirmationResult. After the user provides the code sent to their phone, call firebase.auth.ConfirmationResult.confirm with the code to sign the user in.
This is the default behavior in all applications that uses phone number as login. There is no method in the firebase docs that can restrict this.
you have to use firebase database also with this code to save user info, that way you can achieve your use case