Thursday, May 30, 2013

Android SSO

The documentation of Android's AccountManager is infamously uninformative. AccountManager is available since API level 5 and I got the impression that Google changed it a lot. I am not sure whether it is still work-in-progress. Probably.

So how does Google do SSO for their own services? Not long ago Google introduced Google Play Services

Google Play Services contains an Authenticator that handles all Accounts for "com.google". The Google apps like GMail etc query this Authenticator for access tokens using the Authenticators getAuthToken method. The application can then use this access token to access the API of its backend server.

How can this be secure? How does the Google Play Services SDK (GoogleAuthUtil) know that GMail is a trusted app?
I am guessing here but I think that Google uses the same mechanism that Google recommends for developers. The keys used to sign an Android app are retrievable by the SDK and can be send to the backend. The backend then checks whether the keys match preconfigures keys.
Of course this security has its limits. On a rooted phone or a custom build phone any app can claim to be the e.g. GMail app by replacing the Android library calls that fetch the signing keys. But then Google knows to which user (Google account) a phone is registered to. Maybe this can be used to inform the user that something is going on or the account can be inactivated. Difficult.
(The new Google Play Developer Console helps.)

I think this level of security is acceptable for most consumer cases.

So let's say your company is a mobile games company (Acme Games) and you want SSO between your apps. Now write your own authenticator and put it into an apk e.g. "Acme Services".
Now each of your games can query the existence of the Authenticator for your domain "com.acme".
If it exists then ask for an access token. If it does not exist then the user has to prove to your backend that he knows something only he can know. (Successful login to a third party (e.g. Google+ Sign-In) or plain username and password). In this step you should recommend to install Acme Services because it helps the user to login to future games he will install. (And synchronization services, backup etc).

It is a pity that not each game can contain an Authenticator. In fact it can but I have not tried it out. I do not know what happens if there are several Authenticators claiming to be authoritative for "acme.com". I guess this leads to trouble or else Google would chosen this way for their own apps.
At least it takes up space in each of your app... That is the official reason given by Google:

You're done! The system now recognizes your account type, right alongside all the big name account types like "Google" and "Corporate." You can use the Accounts & Sync Settings page to add an account, and apps that ask for accounts of your custom type will be able to enumerate and authenticate just as they would with any other account type.
Of course, all of this assumes that your account service is actually installed on the device. If only one app will ever access the service, then this isn't a big deal—just bundle the service in the app. But if you want your account service to be used by more than one app, things get trickier. You don't want to bundle the service with all of your apps and have multiple copies of it taking up space on your user's device.
One solution is to place the service in one small, special-purpose APK. When an app wishes to use your custom account type, it can check the device to see if your custom account service is available. If not, it can direct the user to Google Play to download the service. This may seem like a great deal of trouble at first, but compared with the alternative of re-entering credentials for every app that uses your custom account, it's refreshingly easy.


It is a pity that GoogleAuthUtils are not configurable with your domain, your token endpoint etc. Maybe that is asking too much. We are on our own here and have to reimplements GoogleAuthUtils for our purposes.

Through the method described in this post you are creating your own identity silo. Which is OK if your company is big enough and you do not care about the access tokens being useful at other  (your business partners) sites. If you implement your own authenticator then the backend API and token format are all your own responsibility. PROTIP: use OpenID Connect.


OpenID Connect is a profile of OAuth2. Google is recommending it too. Use it!

If you want interoperability later (business partner integration) then being standard compliant make things A LOT easier!


No comments: