Firebase suddenly stopped working, using Anonymous Auth - android

i have set up firebase storage for my app, and added the code for anonymous auth on the app and on the firebase console.
it worked at first, but i dont know why it stopped working, saying that the user does not have permission to access the object
Anonymous auth is correctly set up and i did see it working, code is almost like Google Firebase docs
logcat:
D/FirebaseAuth: signInAnonymously:onComplete:true
D/FirebaseAuth:
onAuthStateChanged:signed_in: (Random auth user id)
... When i request the item from firebase
E/StorageUtil: error getting token java.util.concurrent.ExecutionException: com.google.firebase.FirebaseException: An internal error has occured. [Internal error encountered.]
I/DpmTcmClient: RegisterTcmMonitor
from: com.android.okhttp.TcmIdleTimerMonitor W/NetworkRequest: no auth
token for request E/StorageException: StorageException has occurred.
User does not have permission to access this object.
Code: -13021 HttpResult: 403
Can Someone help?
Declaring Variables
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
on the OnCreate method
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
Log.d("FirebaseAuth", "onAuthStateChanged:signed_in:" + user.getUid());
} else {
// User is signed out
Log.d("FirebaseAuth", "onAuthStateChanged:signed_out");
}
// ...
}
};
mAuth.signInAnonymously()
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d("FirebaseAuth", "signInAnonymously:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Log.w("FirebaseAuth", "signInAnonymously", task.getException());
Toast.makeText(SingleMemeEditor.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
// ...
}
});
and the method that gets from storage:
Bitmap bmp;
final Context lContext = context; //getting the MainActivity Context
final String lFileName = fileName; //filename to download
final String lCatPath = catPath; //internal categorization folder
FirebaseStorage storage = FirebaseStorage.getInstance();
// Create a storage reference from our app
StorageReference storageRef = storage.getReferenceFromUrl(context.getResources().getString(R.string.firebase_bucket));
// Create a reference with an initial file path and name
StorageReference filesRef = storageRef.child("files/" + fileName);
try
{
final File localFile = File.createTempFile("images", "jpg");
filesRef.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>()
{
#Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot)
{
// Local temp file has been created
File file = new File(getDirectory(lContext)
+ File.separator + lCatPath + File.separator + lFileName);
try
{
Boolean b = file.createNewFile();
if(b)
{
FileInputStream in = new FileInputStream(localFile);
FileOutputStream out = new FileOutputStream(file);
// Transfer bytes from in to out
byte[] buf = new byte[(int)localFile.length()];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
Drawable.createFromPath(file.getPath())).getBitmap());
}
catch (IOException ex)
{
// Handle any errors
Log.e("CopyingFromTemp", ex.getMessage());
}
}
}).addOnFailureListener(new OnFailureListener()
{
#Override
public void onFailure(#NonNull Exception ex)
{
// Handle any errors
Log.e("FirebaseDownloadError", ex.getMessage());
}
});
}
catch(Exception ex)
{
Log.e("FirebaseDownloadError", ex.getMessage());
}
also i'm using standard security rules:
match /{allPaths=**} {
allow read, write: if request.auth != null;
}

as Benjamin Wulfe hinted, i deleted the App's data on the phone and it worked, which means that some kind of Token data was stored on the phone and Anonymous Auth was getting an old session data.
so i added a sign out code before signInAnonymously
mAuth.signOut();
and done!
Thanks to you all for the help!
EDIT: I found another method which is better than signing out and in again (which lead to hundreds of unused anonymous users on the firebase console, and that because the app is not in production yet, would have been millions).
this is what i did:
if (mAuth.getCurrentUser() != null)
{
mAuth.getCurrentUser().reload();
}
else
{
mAuth.signInAnonymously()
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>()
{
#Override
public void onComplete(#NonNull Task<AuthResult> task)
{
Log.d("FirebaseAuth", "signInAnonymously:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful())
{
Log.w("FirebaseAuth", "signInAnonymously", task.getException());
Toast.makeText(MainActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
// ...
}
});
}
this just reloads current authenticated (anonymous) user.

The message " W/NetworkRequest: no auth token for request " is key for debugging this issue.
This log message means that Firebase Storage did not see any login in the current context. This includes anonymous logins. It means that no authorization was passed to the backend and the only way this will be allowed is if you set your rules to be completely open (public access) which is not recommended (see below).
//this sets completely open access to your data
allow read, write;
I would review the code you have for logging in and ensure it successfully completes before any storage operation is done.
If you are sure your auth code is correct, try resetting data on the device so that no saved state might be there to mess up the application's authorization information.

You might have to check your RULES for storage in firebase console. By default it is set to only permit to authenticated user only
like this
allow read, write: if request.auth != null;

Sometime its disconnect from firebase database,So Connect your app with firebase authentication in android studio through firebase assistance tool.

Related

check existing and none existing account in firebase auth / Android Java [duplicate]

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();
}
// ...
}
});

Android sign in to APPLE with Firebase

I am implementing apple sign in with Firebase in Android. I have followed the instructions mentioned here : https://help.apple.com/developer-account/#/dev1c0e25352
also created the Key, as mentioned here : https://help.apple.com/developer-account/#/dev77c875b7e
also enabled Apple Sign in from firebase console and added the Service ID, and newly generated Key data to the firebase console.
my Code :
OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com");
List<String> scopes =
new ArrayList<String>() {
{
add("email");
add("name");
}
};
provider.setScopes(scopes);
mAuth.startActivityForSignInWithProvider(this, provider.build())
.addOnSuccessListener(
new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
// Sign-in successful!
Log.d(TAG, "activitySignIn:onSuccess:" + authResult.getUser());
FirebaseUser user = authResult.getUser();
// ...
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "activitySignIn:onFailure", e);
}
});
but i am getting an error, in the OnFailureListener:
The supplied auth credential is malformed or has expired. [ Error getting access token from https://appleid.apple.com, OAuth2 redirect uri is: https://******.firebaseapp.com/__/auth/handler, response: OAuth2TokenResponse{params: error=invalid_client, httpMetadata: HttpMetadata{status=400, cachePolicy=NO_CACHE, cacheDurationJava=null, cacheImmutable=false, staleWhileRevalidate=null, filename=null, lastModified=null, retryAfter=null, headers=HTTP/1.1 200 OK
can anyone help out here.

Get old data from firebase when local user is deleted

Im working on a android app with email-password login.
The user is created in a local sqlite db and in firebase + auth.
Situation: The user uninstalls the app, the local db is deleted. Then the user re-installs the app and wants to login using old credentials, But the user does not exist locally thus the app tries to create a new. - but the user already exist remote in my firebase users table + auth.
Question: How do I query either firebase auth or firebase for the user info only using email, pass and perhaps a few extras.
Most answers I found refer to using the update event from firebase, but at this point it´s not possible as the user is not yet authenticated
I solved it myself.
It was simple and not at all. A part of my fix is below. But in short. I get the user from firebase, then make an update to firebase and then I restore the user in a addValueEventListener(new ValueEventListener()
_fbAuth.signInWithEmailAndPassword(_email, _password).addOnCompleteListener(LoginActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
Log.d(TAG, "Firebase login success");
FirebaseUser fbUser = _fbAuth.getCurrentUser();
String uid = fbUser.getUid();
FireBaseWriteHelper wh = new FireBaseWriteHelper();
FireBaseReadHelper fireBaseReadHelper = new FireBaseReadHelper(getApplicationContext(), uid, Util.VERSION_KEY_FREE);
DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
Date date = new Date();
wh.UpdateUserLastLogIn(uid, format.format(date));
_user = _userHelper.CheckUserExist(_email, _password);
mPasswordView.setError(null);
mEmailView.setError(null);
} else {
try {
throw task.getException();
} catch (FirebaseAuthInvalidUserException e) {
} catch (FirebaseAuthInvalidCredentialsException e) {
} catch (FirebaseNetworkException e) {
} catch (Exception e) {
}
}
}
});
You can use the Firebase in Offline mode. You don't need to use two databases. Guide here.

GoogleAuthProvider.getCredential method does not work for me

I am trying to follow this tutorial.
And I created this firebaseAuthWithGoogle function:
public void firebaseAuthWithGoogle(Activity context,FirebaseAuth mAuth, GoogleSignInAccount acct) {
Log.i(TAG, "firebaseAuthWithGoogle:" + acct.getId());
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mAuth.signInWithCredential(credential)
.addOnCompleteListener(context, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.i(TAG, "firebase signInWithCredential:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Log.i(TAG, "firebase signInWithCredential" + task.getException());
}
// ...
}
});
}
Which I call from here:
final GoogleSignInAccount acct = result.getSignInAccount();
AsyncTask asyncTask = new AsyncTask() {
#Override
protected Object doInBackground(Object[] params) {
try{
String scope = "oauth2:" + Scopes.PROFILE;
Account account = new Account(acct.getEmail(), "com.google");
final String token = GoogleAuthUtil.getToken(PSSignInFlowActivity.this, account, scope); PSSocialService.getInstance().firebaseAuthWithGoogle(PSSignInFlowActivity.this, PSApplicationClass.getInstance().mAuth, acct);
}catch (Exception e){
Log.e("","firebase error trying to get client secret : " + e.getMessage());
}
return null;
}
};
asyncTask.execute();
My idToken is: firebaseAuthWithGoogle:1024xxxxxxxxxxxxxx956 (so it is not null, added it maybe I'm not sending what I'm suppopsed too?)
But when I debug, i get this error:
Must specify an idToken or an accessToken.
What am I doing wrong? They use the same logic on the tutorial
PS: I am on compile 'com.google.firebase:firebase-auth:10.2.0' if it matters
EDIT: I noticed that acct.getIdToken() returns null, why is that?
Shouldn't the GoogleSignInAccount have a idToken?
I was logging out the acct.getId() which is the 1024xxxxxxxxxxxxx956 I wrote upper.
EDIT2: I added to my GSO this option:
.requestIdToken(serverID)
And now I get the idToken, but I get this response back:
04-05 10:34:16.388: I/PSSocialService(6285): firebase signInWithCredentialcom.google.firebase.FirebaseException: An internal error has occurred. [ Invalid Idp Response ]
serverID is: 264xxxxxxxxxx27.apps.googleusercontent.com
Is that the correct value I should use?
In the tutorial they use:
.requestIdToken(getString(R.string.default_web_client_id))
But I tried that, and it crashes, cause It says I need to use the same clientID.
I use serverID for .requestServerAuthCode(serverID) and I guess that is why
In the firebase console, for Authentification/Providers/Google it is needed to add the all external cliend ids, in order to whitelist them. This is why it would not work for me

Firebase User's display name and photo url is not retrieved

I am developing an Android App using Firebase, In my app I am using Firebase Anonymous Login and Google sign In.
When the application starts if the user is not Logged In, then I am using Anonymous Authentication to log the user in.
Afterwards when user chooses to Sign In using Google, then I am converting Anonymous Account to a permanent account.
My issue over here is, When user's account is converted from Anonymous Account to permanent account (using Google Sign In in this case), I am not getting User's Display Name and Photo Url.
For converting from Anonymous Account to permanent account I am using below code.
AuthCredential credential = GoogleAuthProvider.getCredential(googleIdToken, null);
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
Log.d(TAG, "linkWithCredential:onComplete:" + task.isSuccessful());
if (!task.isSuccessful()) {
Toast.makeText(AnonymousAuthActivity.this, "Authentication failed.",Toast.LENGTH_SHORT).show();
//If Google Account already linked up with other UID
Tasks.await(mAuth.signInWithCredential(credential)).getUser();
}
}
});
After the Sign In process completes, the AuthStateListener onAuthStateChanged is called, Then in onAuthStateChanged I am extracting User's Display Name, User's Photo Url and User's Email. Below is the onAuthStateChanged code.
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null && !(user.isAnonymous())) {
Log.d("userDetails", "UID: " + user.getUid());
Log.d("userDetails", "Name: " + user.getDisplayName());
Log.d("userDetails", "PhotoUrl: " + user.getPhotoUrl().toString());
Log.d("userDetails", "Email: " + user.getEmail());
}
In the log I am getting null for user.getDisplayName() and user.getPhotoUrl()
I don't understand what I am doing wrong. Please help.
Thanks & Regards,
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
user.getProviderData();
loop through providers and get the desired provider
userData.getProviderId().equals(GoogleAuthProvider.PROVIDER_ID)
Uri photoUrl = userData.getPhotoUrl();
When linking accounts (or even on every sign in), call this function
Future<void> updateMissingUserPropertise(User user) async {
if (user.photoURL == null) await user.updatePhotoURL(user.providerData[0].photoURL);
if (user.displayName == null) await user.updateDisplayName(user.providerData[0].displayName);
}
In order to support multiple providers, each of which might hold a different name, photo, or phone number, Firebase auth does not modify the user properties when linking accounts.
Even if the user signs out later and signs in with Google, or any other federated account, it does not change the user properties.
The function above 'fixes' the missing user properties by grabbing them from the first provider, which is Google in your case, and setting them in the user properties for good.
The more complex version of this function, which supports the case of multiple providers, loops through the providers until a DisplayName or a photoURL are found.
Future<void> updateMissingUserPropertise(User user) async {
if (user.photoURL == null) {
user.providerData.forEach((provider) async {
if (provider.photoURL != null) {
await user.updatePhotoURL(provider.photoURL);
return;
}
});
}
if (user.displayName == null) {
user.providerData.forEach((provider) async {
if (provider.displayName != null) {
await user.updateDisplayName(provider.displayName);
return;
}
});
}
}

Categories

Resources