firebase / FirebaseUI-Android

Optimized UI components for Firebase
https://firebaseopensource.com/projects/firebase/firebaseui-android/
Apache License 2.0
4.63k stars 1.84k forks source link

Support Android AccountManager #486

Open bpappin opened 7 years ago

bpappin commented 7 years ago

I'm trying to integrate Firebase Auth with the Android SyncManager and AccountManager, which is proving to be very cumbersome.

It would be great if we have a FirebaseAuthUI-Android Authenticator stub we could simply reference, which would make setup quick and easy.

samtstern commented 7 years ago

@bpappin thanks for the idea! I don't think we'll be incorporating this into FirebaseUI since it lacks a 'UI' component but I agree this would be a very useful recipe for a Firebase blog post or another venue.

I am going to close the issue for the reason above, but could you share some more about your experience? Where did you get stuck, and did you ever get it working? I'd love to see what you got done.

bpappin commented 7 years ago

Actually, I added it here specifically because it does require a UI component, and FirebaseUI-Android does not support it.

bpappin commented 7 years ago

I think you should reopen this issue until you can investigate how it needs to work. This blog article gives a fairly easy to read breakdown of the components, as you can see, the activity used is pretty important.

http://blog.udinic.com/2013/04/24/write-your-own-android-authenticator/

The only thing that he shouldn't do is store the password.

bpappin commented 7 years ago

Let me know if I need to reopen this in a new issue. Because the worst of the incompatibility is on the UI side.

jpventura commented 7 years ago

@bpappin https://github.com/jpventura/FirebaseAccountAuthenticator. I refactored @udinic app to Firebase 3.

jpventura commented 7 years ago

@samtstern, @bpappin I am still trying to solve the password store issue.

Even calling AccountManager.peekAuthToken immediatly after the token be saved, it returns null.

bpappin commented 7 years ago

@jpventura Hey, nice, I'll take a look.

AccountManager.peekAuthToken should really not be used, except internally in the authenticator implementation. However, it should not be returning null if you are authenticating. I have not looked at the code yet, but I suspect you are not setting the callback properties that store the token. You could also do it directly upon authentication.

Take a look at this example under Creating the Activity.

http://blog.udinic.com/2013/04/24/write-your-own-android-authenticator/

Notice that the token is set as response params, and directly on the AccountManager. He's doing this to work around a perceived problem hat I'm not sure he needs to worry about, but its still nice clear code. Also notice that is is storing the password, and has to invent a param to do it... don't do that part, just leave it out :)

As for the password, you actually don't want to store the password. It's one thing that almost every example gets wrong. The idea is that you get the token and use that for subsequent calls. If the token expires in a non-recoverable way, or the server/client detect a security breach, the token can be expired from either side, forcing the user to re-authenticate. You want the user to re-authenticate with information that only the user knows, and is not stored on the phone.

The mechanism for how that works is built into he sync manager. A simple example is: If the token is bad during a sync (which is happening in the background) the syncmanager service will notify the user in the notification bar; when the user click the notification, it simply opens your app, which can see that the user is not authenticated, and requests login.

This is actually what you want, since tokens are supposed to be long lived. By not including the password, a security breach doesn't actually give the breacher full access. If you want the tokens to rotate, you can implement one of several common models (dual tokens, or token refresh, etc.).

bpappin commented 7 years ago

@jpventura ok, took a quick peek, and am not sure, I don't have time now to dig deeper.

However, the goal with integrating it with firebase-ui would be to get all the one stop shopping authenticator features in one place. To do that we are going to have to fork their repo, and refactor the authenticator activity. if we are just hooking into the FirebaseAuth, we can do that without a whole lot of trouble.

jpventura commented 7 years ago

@bpappin

TL; DR

Details

Once you authenticate using email/password, Facebook, Google+, etc, Firebase authentication service returns a JSON Web Token (RSA Signature with SHA-256).

The simpler approach is cache the token indefinitely and prompt the sign in screen when the sign in fails, so we will never have to decode the JWT string (this is the approach I have adopted).

The complex one is obtain the expiration date-time from the token using a JWT decoder and stored at the account manager was well:

{
    "iss": "https://securetoken.google.com/example-a510e",
    "aud": "example-a510e",
    "auth_time": 1495387631,
    "user_id": "JtzefPcuYDhhTUkE9P3aa8yDwxy1",
    "sub": "JtzefPcuYDhhTUkE9P3aa8yDwxy1",
    "iat": 1495387631,
    "exp": 1495391231, /* 2017-05-21T18:27:11.000Z */
    "email": "john@email.com",
    "email_verified": false,
    "firebase": {
        "identities": {
        "email": [
            "john@email.com"
        ]
        },
        "sign_in_provider": "password"
    }
}

The commit a714f09c provides several good references about JWT and Android account manager security.

pwpriority commented 6 years ago

Actually Account Manager has two UI components (or three if you separate signin/signup) plus the UI in the device settings/accounts. I would like to know how to implement this feature as well