Implementing Signing Out, Deleting Accounts and Upgrading Anonymous users with FirebaseUI Authentication

This is a continuation of my last article on how to add Firebase Authentication to your app using FirebaseUI. It’s not required, but if you want to follow along from the beginning you can check part 1 below:

Alternatively if you just want the code, I created a sample app for this project that you can find on GitHub here:

Signing Out

If you’re letting a user sign in to your app, you must let them sign out! It’s an essential function and FirebaseUI makes it easy to implement:

Step 1:

First you will have to design a settings screen to give the user one place to manage their account settings. For the purposes of this article I have designed a simple screen allowing the user to sign out, delete their account and, if they signed in anonymously, create a new account to upgrade to. However, when designing your settings screen keep in mind that not all options apply to all users:

Signing out only applies to users who have not signed in anonymously. If a user is anonymous they do not have an account, so there's nothing to sign out of.

Deleting an account works the same. If a user is anonymous they do not have an account, so there’s no account to delete.

Creating an account is the opposite. An anonymous user needs to be shown this option so that if they wish to upgrade their account to a permanent one they can do so. However, a signed in user would have no need to create an account again (at least, while they are currently signed in), so this option should be hidden for them.

Note: If you are still collecting data from an anonymous user and storing it locally or remotely you must inform the user of a way they can delete their data. You might not think it is necessary, but even if you are a small developer it is imperative you give your users control over their data to comply with privacy laws.

Step 2:

Once you’ve designed the XML you have to map the buttons to perform the proper operations. Let’s start by showing you the code to sign the user out:

First you will need to create an onClickListener for the sign out button:

sign_out.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

inside the onClickListener you will need to get an instance of the AuthUI class, call the sign out method and pass in the context (We’re using Fragments which is why the context is passed in as requireContext(), if you are using an Activity it might be different):

AuthUI.getInstance().signOut(requireContext());

Now we have to add two things: an onCompleteListener and an OnFailureListener. After the user is successfully signed out we want to send them back to the initial FirebaseUI sign in screen. However, if the signing out operations fails for whatever reason we want to inform the user, such as by showing a Toast.

Here is the code for both:

AuthUI.getInstance().signOut(requireContext()).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {

Intent main_firebaseUI = new Intent(requireContext(), FirebaseUI_LogInScreen.class);
main_firebaseUI.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(main_firebaseUI);

Toast.makeText(requireContext(), "You have been signed out", Toast.LENGTH_SHORT).show();

}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {

Toast.makeText(requireContext(), "Failed to sign out, please try again later", Toast.LENGTH_SHORT).show();

}
});

Now let’s dissect that code for the OnCompleteListener:

Intent main_firebaseUI = new Intent(requireContext(), FirebaseUI_LogInScreen.class);
main_firebaseUI.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(main_firebaseUI);

The above code is simply an Intent that, upon successfully signing out, will send the user back to the initial FirebaseUI sign in screen. The flags that were added:

main_firebaseUI.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

essentially perform the action of clearing the stack and setting the sign in screen as a new Activity to disallow the user from going back to the settings screen again.

The Toast:

Toast.makeText(requireContext(), "You have been signed out", Toast.LENGTH_SHORT).show();

is used to give feedback to the user that the operation was successful.

For the OnFailureListener:

Toast.makeText(requireContext(), "Failed to sign out, please try again later", Toast.LENGTH_SHORT).show();

we simply display a Toast informing the user that the signing out operation has failed and to try again later.

Deleting an Account

Note: As of this writing (November 2019) deleting an account using FirebaseUI is not really supported. In order to delete an account using the Firebase SDK a user is required to have re-authenticated (signed in) recently within the last ~5 minutes. The standard Firebase SDK allows for re-authentication. However, FirebaseUI currently does not have a method for re-authenticating a user automatically. Due to this you have two options for deleting a user’s account:

  1. The easiest, yet most user unfriendly way, to delete an account would be to instruct the user to sign out, sign in again, then delete their account. As long as the user does this within ~5 minutes the operation will be successful, despite the fact that it’s not the proper way to do so.
  2. The best, yet more tedious way, is to delete a user is manually. You can allow the user the send you an account deletion request, manually find the user in the Firebase console and delete their account. You can achieve this by using an email intent to send the user to their email application and send you an email, pre-populated with their user ID. You could also create a form using a service such as Google Forms and use WebView to direct users to your form, where they can populate the form with the information they used to sign-in (e-mail, phone number, etc…) to be sent to you. From there you can find the information they entered in the Firebase console and delete the account manually as well.

If FirebaseUI ever adds a re-authenticate function I will update this story with instructions on how to implement it. Also, there is currently an open issue for this on the Firebase-UI GitHub since January 2017 which you can monitor yourself here: https://github.com/firebase/FirebaseUI-Android/issues/563.

Nevertheless, for information on deleting an account if you wish to implement it:

Allowing a user to delete their account is important as it allows the user to have control over their account and data. As it is permanent, it is also a serious operation, and you must convey that seriousness to the user. With signing out it’s okay to have the operation be a single button press. Deleting an account however, should require additional steps, such as a confirmation dialog, to prevent accidental presses. For the sake of simplicity we will just show you how to delete an account.

The code for deleting an account almost exactly the same as signing out, except instead of calling the signOut method you call the delete method:

AuthUI.getInstance().delete(requireContext());

The rest of the code is essentially the same with the only differences being the Toast text:

AuthUI.getInstance().delete(requireContext()).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
Toast.makeText(requireContext(), "Your account has been deleted", Toast.LENGTH_SHORT).show();

Intent main_firebaseUI = new Intent(requireContext(), FirebaseUI_LogInScreen.class);
main_firebaseUI.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(main_firebaseUI);

}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {

Toast.makeText(requireContext(), "Failed to delete account, please try again later", Toast.LENGTH_SHORT).show();

}
});

Upgrading Anonymous Users

Upgrading Anonymous users is a necessity if you allow anonymous authentication. Upgrading anon users require some additional steps though:

First you will have to create a secondary FirebaseUI sign-in screen. If you send the user back to the initial sign in screen, as with signing out, then they will see the “Continue as guest” button again which is not good user design. To create this secondary screen make sure to create a new Activity. This uses very similar code from the previous article so you can copy most of it, however, we need to add the .enableAnonymousUsersAutoUpgrade() method, the .setIsSmartLockEnabled(false) method and remove the AnonymousBuilder from the list of providers:

List<AuthUI.IdpConfig> providers = Arrays.asList(
new AuthUI.IdpConfig.EmailBuilder().build(),
new AuthUI.IdpConfig.PhoneBuilder().build(),
new AuthUI.IdpConfig.GoogleBuilder().build());

startActivityForResult(AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.setTheme(R.style.AppTheme)
.setLogo(R.drawable.baseline_android_black_48)
.enableAnonymousUsersAutoUpgrade()
.setIsSmartLockEnabled(false)
.build(), RC_SIGN_IN);

This:

.enableAnonymousUsersAutoUpgrade()

Allows FirebaseUI to automatically take an anonymous account and upgrade it to a permanent one.

This code:

.setIsSmartLockEnabled(false)

Prevents Google’s Smart Lock account picker from showing an account chooser to the user or potentially auto signing in a user using an account they may have used previously.

Additionally, be sure to change the RC_SIGN_IN constant to have a different value from your first sign-in screen. For the first screen we used 123, so now we can use 456:

private static final int RC_SIGN_IN = 456;

In onCreate there is no need to check if the user is null or not like we did on the initial screen, so we can just call our showFirebaseUI(); method.

The onActivityResult method will be the same except we need to add some flags to clear the stack and start a new activity:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == RC_SIGN_IN) {
if (resultCode == RESULT_OK) {
Intent homeIntent = new Intent(this, NavigationActivity.class);
homeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(homeIntent);
finish();
user.reload();

} else {
finish();
}
}
}

Finally, the onClickListener will just be a simple Intent to send the user to the Create account screen. Unlike signing out or deleting an account we don’t have to clear the back stack or start a new activity as the user might want to go back:

Intent anon_create_account = new Intent(requireContext(), FirebaseUI_AnonUpgradeScreen.class);
startActivity(anon_create_account);

Congratulations! You should now know how to sign a user out, delete an account and upgrade an anonymous user. If you have any questions leave a response below and I will answer it. Be sure to check out my other tutorials and follow for more!

Software Engineer specializing in native Android Development with Java