13

Under The Hood

I am using Firebase Authentication in my Android app to sign up/in users using Google, Facebook and Email/Password. So far, almost everything works fine except for a single scenario.

The Scenario

I need to disable or delete user accounts from the Firebase console sometimes to ban some users of my app.

In that case, when I disable or delete that particular user, the user must get logged out from the app instantly and should not be able to use it any further.

The Bug

I have used the AuthStateListener to listen for authentication state changes and log out the user automatically as soon as their account is disabled or deleted.

FirebaseAuth.getInstance().addAuthStateListener(firebaseAuth -> {
            if (firebaseAuth.getCurrentUser() == null) {
                Intent intent = AuthFlowActivity.getCallingIntent(AuthFlowActivity.FORCE_LOGOUT);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                startActivity(intent);
                activityExitAnimation(BaseAppActivity.this);
            }
        });

But I have never seen the AuthStateListener fire any events for these actions. So I am unable to log out the user instantly and the user can still keep on using the app.

I would appreciate if anyone can help in resolving this issue.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Aritra Roy
  • 15,355
  • 10
  • 73
  • 107

1 Answers1

18

Disabling or deleting a user account does not fire an auth state change. Nor should it, the user is still authenticated. In at most an hour, Firebase Authentication will try to refresh the access token for the user. That refresh will fail, at which point the user will become unauthenticated and the auth state change event will fire.

If you're looking to revoke the user's authorization immediately, you will have to do so in another part of your application logic. A common way to do this is by having a blacklist in your application, e.g. in the Firebase Database:

/bannedUsers
    uidOfBannedUser: true

Now when you delete/disable a user's account in the Autentication panel, you also add their uid to the list of banned users in the database.

The database can then be secured against access from unauthorized users by adding a clause to your database security rules, e.g.

{
  "rules": {
    "bannedUsers": {
      ".read": true,
      ".write": false // only admins can write these
    },
    "messages": {
      ".read": "auth != null && !root.child('bannedUsers').child(auth.uid).exists()"
    }
  }
}

If you use a different back-end, the implementation will be different. But a blacklist like this is a common approach to ban users. You'll find that you may even care little enough about their authentication that you only ban them, instead of deleting their credentials (which they could simply recreate).

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks a lot for the helping me out on this. Not I am clear on which approach I should be taking. On the same note, I would like to know if the AuthStateChange listeners do fire if the access token gets expired? And in how much time does the tokens get expired? – Aritra Roy Jul 13 '16 at 14:56
  • The short-lived access tokens expire in an hour (hence my remark that it will take at most an hour). If the token cannot be refreshed that will definitely fire an auth state change. If the token refresh it may also call the method, but I haven't checked in a while (that one is more debatable). – Frank van Puffelen Jul 14 '16 at 01:42
  • 1
    Thanks Frank. But I have observed that, I have logged in with my Google account to the app and is still logged in after 2 days. This is what I wanted to know. Once I log in, when does these tokens expire and the user must re-login to get fresh tokens? – Aritra Roy Jul 14 '16 at 04:45
  • The access tokens will auto-refresh, so in normal situations the user will never have to sign in again. But certain changes to the user account (such as a password change, or disabling/deleting the credentials) will make the auth-refresh fail and end the user's session. – Frank van Puffelen Jul 14 '16 at 15:08
  • Thanks Frank. That was really helpful. – Aritra Roy Jul 15 '16 at 07:34
  • 1
    hey @FrankvanPuffelen thanks a billion for this explanation. I must add my vote that: when an account is deleted, IMO that is surely (!!) a change of state. IMO you should get a state change immediately. {Note that indeed you are saying, effectively, "you'll get an auth after about an hour". Really, why? It's either a state change or not.} It's a rare case where I disagree with Firebase! – Fattie Oct 27 '17 at 14:50
  • 1
    (the tip of having a typical blacklist, is a great technique but not, really, relevant to literally observing if the user "still exists!") – Fattie Oct 27 '17 at 14:51
  • This is a great answer as always from @FrankvanPuffelen. I understand the difference between authentication and authorization, but I struggle to come up with any valid use case where it would make sense to keep a user authenticated when they are disabled or deleted. Am I missing something? – telliks Mar 20 '18 at 14:12