Firebase Authentication in Jetpack Compose
Handle Firebase Authentication Errors
Learn how to handle Firebase Auth Errors when working and Firebase Authentication
In the previous parts of this series, we implemented
Handle Auth Errors
Let’s look at some of the errors that needs to be handled when you have anonymous and multiple providers authentication.
Scenario 1
The user signed-in and out using one of the providers, then the user skipped the login process (i.e. anonymously authenticated), in this case two Firebase auth users will be created, one user with the signed-in provider, and the other user is anonymous.
The user can also be signed-in from a device, and skipped login on another device.
In the screenshot below, the user is authenticated using Apple provider from the iOS app for this project..
Scenario 2
The user already signed-in using a provider, and then you try to link accounts using another providers (which is already linked).
In this tutorial series, Scenario 2 was already handled, and so it won’t happen, but it could happen if you have the option of linking different providers in your app settings, so in order to test this scenario, comment the code inside onClick
callback block of the sign-out button and just leave openLoginDialog.value = true
, to show LoginScreen
.
onClick = {
// if (authState != AuthState.SignedIn)
openLoginDialog.value = true
// else
// authViewModel.signOut()
},
Solution
authenticateUser(credentials:)
function inside AuthRepositoryImpl
we checked if the current firebase user is not null, then link account, otherwise sign-in (as explained in Part 1: Anonymous Authentication).
In scenario 1, if the user is anonymously authenticated and you are trying to link the anonymous account with a credential that is already in use (if you’re trying to link with the same provider) or email address is used by another account (if you’re trying to link with different provider), so link(with:)
will throw one of these errors:
FirebaseAuthException: "ERROR_CREDENTIAL_ALREADY_IN_USE"
: Indicates an attempt to link with a credential that has already been linked with a different Firebase account.FirebaseAuthException: "ERROR_EMAIL_ALREADY_IN_USE"
: Indicates the email asserted by the credential is already in use by an existing account.
In scenario 2, if the user is authenticated with Google, and you are trying to link the account also with the Google credentials, so link(with:)
will throw the following error:
FirebaseException: "User has already been linked to the given provider."
: Indicates an attempt to link a provider to which the account is already linked.
In these cases, switch to signIn(credential:)
instead, as follows:
Scenario 1 solution:
Add another catch block in authLink(credentials:)
that catches the FirebaseAuthException
errors to check the error code.
catch (error: FirebaseAuthException) {
when (error.errorCode) {
"ERROR_CREDENTIAL_ALREADY_IN_USE",
"ERROR_EMAIL_ALREADY_IN_USE" -> {
Log.e(TAG, "FirebaseAuthError: authLink(credential:) failed, ${error.message}")
return authSignIn(credential)
}
}
Response.Failure(error)
}
Scenario 2 solution
- First solution is to prevent this from happening by checking on auth state as done before in
onClick
callback block inside sign-out button, and to hide sign-in whenever the user is authenticated with any provider. - Second solution is to add another catch block that catches the
FirebaseException
errors and check if the error message contains the following message. (using theFirebaseException
is optional, you can useException
as well because in this case we check the error message not error code!)
catch (error: FirebaseException) {
error.message?.let {
if (it.contains("User has already been linked to the given provider" )) {
return authSignIn(credential)
}
}
Log.e(TAG, "FirebaseError: authLink(credential:) failed, ${error.message}")
Response.Failure(error)
}
Be aware that now you don’t have any reference to the anonymous account anymore, if you have associated data (e.g. Firestore) that uses the data from firebase auth user, it’s recommended to migrate or merge data between accounts.
Resources
“ Everyone has something to learn. Everyone has something to teach.” ~ Paul Hudson