Error while trying to re-authenticate on Firebase using Google-sign-in credentials

Viewed 1424

tl;dr

(ID Token issued at 1589401401 is stale to sign-in.)


The problem:

My app using Google Sign-in with Firebase. After the user loged in, he have the option to remove his account which its also deletes his user from firebase auth. Sign in works totally fine. Deleting user from firebase also works as expected.

The error happens only when the user was logged-in while ago, an hour or so before he tries to delete his account.

ERROR deleting user: task fail 
com.google.firebase.auth.FirebaseAuthInvalidCredentialsException:
The supplied auth credential is malformed or has expired.
[ ID Token issued at 1589401401 is stale to sign-in. ]

More details:

Firebase demands recent authentication before sensitive actions like account removing therefore i'm using "user.reauthenticate(credential)" before "user.delete()"

Removing user code flow:

user.delete() -> if error: FirebaseAuthRecentLoginRequiredException -> user.reauthenticate(credential) -> user.delete()

Whats weird is that re-authentication actually succeed if only about 30 minutes passed from the last log in but it fails if it's was about an hour or more. Also, it was working perfectly before but i can't manage to know whats changed that now i get this error

I'm assuming that I can just force the user sign in again using google sign-in but as far as I know it's not mandatory for google sign-in method as I get the user id token using: GoogleSignIn.getLastSignedInAccount() and pass the token id as credentials for reauthenticate()

My code:

FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();

    private void userDelete() {
        Log.d(TAG, "userDelete: Deleting user...");
        user.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                Log.d(TAG, "onSuccess: User deleted");
                Log.d(TAG, "userDelete: Signing out...");
                signOut(); //Signing out from Firebase and Google log-in
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.d(TAG, "onFailure: Error deleteing user, probebly need to reauthenticate");
                Log.e(TAG, "onFailure: Error:", e);
                reAuthenticateUser(); //reauth and delete user
            }
        });


    }

Re authenticating user if getting user deletion error:

    private void reAuthenticateUser() {
        Log.d(TAG, "reAuthenticateUser: Reauthenticating");
        final FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
// Get the account
        GoogleSignInAccount signInAccount = GoogleSignIn.getLastSignedInAccount(getContext());
        if (signInAccount != null) {
            AuthCredential credential = GoogleAuthProvider.getCredential(signInAccount.getIdToken(), null);
            user.reauthenticate(credential).addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "Reauthenticated.");
                        Log.d(TAG, "onComplete: Try to delete user again...");
                        user.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {
                                Log.d(TAG, "onSuccess: user deleted successfully");
                                Log.d(TAG, "onComplete: signing out...");
                                signOut();
                            }
                        });
                    } else {
                        Log.e(TAG, "onComplete: ERROR deleting user: task fail", task.getException());
                    }
                }
            });
        } else {
            Log.d(TAG, "Error: reAuthenticateUser: user account is null");
        }

    }

Signing out after User removal:

private void signOut() {
        //sign out from firebase
        FirebaseAuth.getInstance().signOut();
        //sign out from "google sign in"
        googleSignInClient.signOut().addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                //Get back to login screen
                Intent intent = new Intent(getContext(), LoginActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(intent);
                getActivity().finish();
            }
        });
    }

The error:

D/Settings fragment:: onFailure: Error deleteing user, probebly need to reauthenticate E/Settings fragment:: onFailure: Error:
    com.google.firebase.auth.FirebaseAuthRecentLoginRequiredException: This operation is sensitive and requires recent authentication. Log in again before retrying this request.
        at com.google.firebase.auth.api.internal.zzdx.zza(com.google.firebase:firebase-auth@@19.1.0:4)
        at com.google.firebase.auth.api.internal.zzfa.zza(com.google.firebase:firebase-auth@@19.1.0:21)
        at com.google.firebase.auth.api.internal.zzet.zza(com.google.firebase:firebase-auth@@19.1.0:34)
        at com.google.firebase.auth.api.internal.zzev.zza(com.google.firebase:firebase-auth@@19.1.0:74)
        at com.google.firebase.auth.api.internal.zzed.zza(com.google.firebase:firebase-auth@@19.1.0:18)
        at com.google.android.gms.internal.firebase_auth.zza.onTransact(com.google.firebase:firebase-auth@@19.1.0:13)
        at android.os.Binder.execTransactInternal(Binder.java:1021)
        at android.os.Binder.execTransact(Binder.java:994) D/Settings fragment:: reAuthenticateUser: Reauthenticating I/BiChannelGoogleApi: [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzao@da6aa2a E/Settings fragment:: onComplete: ERROR deleting user: task fail
    com.google.firebase.auth.FirebaseAuthInvalidCredentialsException: The supplied auth credential is malformed or has expired. [ ID Token issued at 1589401401 is stale to sign-in. ]
        at com.google.firebase.auth.api.internal.zzdx.zza(com.google.firebase:firebase-auth@@19.1.0:30)
        at com.google.firebase.auth.api.internal.zzfa.zza(com.google.firebase:firebase-auth@@19.1.0:21)
        at com.google.firebase.auth.api.internal.zzet.zza(com.google.firebase:firebase-auth@@19.1.0:34)
        at com.google.firebase.auth.api.internal.zzev.zza(com.google.firebase:firebase-auth@@19.1.0:74)
        at com.google.firebase.auth.api.internal.zzed.zza(com.google.firebase:firebase-auth@@19.1.0:18)
        at com.google.android.gms.internal.firebase_auth.zza.onTransact(com.google.firebase:firebase-auth@@19.1.0:13)
        at android.os.Binder.execTransactInternal(Binder.java:1021)
        at android.os.Binder.execTransact(Binder.java:994)

Also, here the (handled ) error I get if trying to remove user after about 15-30 minute from last log in. in this case the re authentication works as expected.

D/Settings fragment:: userDelete: Deleting user... I/BiChannelGoogleApi: [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzaq@c066c75 D/Settings fragment:: onFailure: Error deleteing user, probebly need to reauthenticate E/Settings fragment:: onFailure: Error:
    com.google.firebase.auth.FirebaseAuthRecentLoginRequiredException: This operation is sensitive and requires recent authentication. Log in again before retrying this request.
        at com.google.firebase.auth.api.internal.zzeh.zza(com.google.firebase:firebase-auth@@19.3.1:4)
        at com.google.firebase.auth.api.internal.zzfo.zza(com.google.firebase:firebase-auth@@19.3.1:21)
        at com.google.firebase.auth.api.internal.zzfe.zza(com.google.firebase:firebase-auth@@19.3.1:33)
        at com.google.firebase.auth.api.internal.zzfg.zza(com.google.firebase:firebase-auth@@19.3.1:74)
        at com.google.firebase.auth.api.internal.zzen.zza(com.google.firebase:firebase-auth@@19.3.1:18)
        at com.google.android.gms.internal.firebase_auth.zza.onTransact(com.google.firebase:firebase-auth@@19.3.1:13)
        at android.os.Binder.execTransactInternal(Binder.java:1021)
        at android.os.Binder.execTransact(Binder.java:994) D/Settings fragment:: reAuthenticateUser: Reauthenticating I/BiChannelGoogleApi: [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzaq@c066c75 D/FirebaseAuth: Notifying id token listeners about user ( OF22mQlCILNAirW9tN87SV8WAiY2 ). D/Settings fragment:: Reauthenticated. D/Settings fragment:: onComplete: Try to delete user again... I/BiChannelGoogleApi: [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzaq@c066c75 D/FirebaseAuth: Notifying id token listeners about a sign-out event.
    Notifying auth state listeners about a sign-out event. D/Settings fragment:: onSuccess: user deleted successfully

Thanks

1 Answers

So i've ended up asking the user to sign-in again.

Didn't find any solution for this besides forcing the user to get a refreshed token by sign-in again. As the Firebase documentation indicates: "Firebase ID tokens are short lived and last for an hour".

Firebase authentication is invoked in case of a risky operation such as deleting a user. "Silent sign-in" is also not possible in this case.

I think the best practice for deleting a Firebase user is to first try re-authentication (If re-authentication fails you anyway won't be able to delete the user) then if it's fail, ask the user to sign in again or initiate the-sign in sequence.

Related