Google+ Sign-In & Multiple Applications In The API Console

Applications which access Google APIs are configured in the API console as 'projects'. Each project can contain multiple client IDs, and each client ID can represent a different variant of the application: for example an Android client ID, a web client ID, and an iOS client ID. There can multiple of each, so there might be different client IDs for two different versions of an Android application within the same API console project.

One common question is whether a developer should group their applications under a single API console project, or have separate projects for each. While it's pretty easy to see that FooPlayer iOS, FooPlayer Android and FooPlayer.com should all be under the same project, the question is what to do with a situation where there are actual differences other than platform, such as FooPlayer Pro and FooPlayer Free.

As a rule of thumb, if the different apps provide similar core functionality, they should be one project. For example, if an application has a free and a pro version, or if there are multiple country specific versions of an application or site, they should be a single Google API console project. On the other hand, if the applications have different brands, then that's usually a good sign they should have separate API console projects.

To works out what's best for your app though, it can also be helpful to think about the tradeoffs of having a shared project versus separate.

The benefits of a shared project:

Cross client SSO

If a user has signed in on the web and subsequently opens an Android application from the same API console project then they will be seamlessly signed in to the Android app (presuming they're authenticated on the device with the same Google account). The same is true in the opposite situation, starting on Android then moving to the web. This does require that the OAuth 2.0 scopes and app activity types requested in both apps are the same - if not, that tends to be a smell that the applications should really be in separate projects.

Shared quota

Most apps won't need any extra quota for the main Google+ Sign-In APIs, but if using non sign-in APIs or other Google services they may need extra quota allocated. This is done at the project level so all client IDs in that project pull from same bucket, which is easier than getting approvals for quota increases multiple times.

All insights in one place

Google+ platform insights are enabled by linking a Google+ page with a project, and will give statistics based on the activities written and sign-ins for all client IDs in that project. If that sounds like a good thing, that's a good indication the apps should be in the same project.

The downsides of a shared project:

Deep link application ordering and installs

When a user shares from an application to Google+, the share can include a deep link ID. When the reader taps the link in the Google+ application on iOS or Android, they are taken straight to the appropriate Android or iOS application, or to the Play or App store if the app is not installed. If there are multiple apps in the project for either platform, then each of these behaviours will depend on which are installed, and the order they are defined in the API console. So, lets say the project contains:

  • Match-3-tastic!
  • FooPlayer Free
  • FooPlayer Pro

If user A shares from FooPlayer Free, and user B taps the link, then user B will be taken to the first app that they have installed based on the order in the API console. If user B had FooPlayer Free and FooPlayer Pro installed, they would be taken to FooPlayer Free. If they didn't have any installed the same order is followed, they would be taken to the install page for Match-3-tastic. If the apps are all able to handle the deep link, this is an indication they should be in separate projects.

OTA Android installs

If an application has multiple Android applications, only one can be specified in the apppackagename parameter on the web sign-in button to be installed over the air. If that app is installed, the user won't be prompted to install one of the others in the project, even if they don't have it.

Single API console branding

When the user signs in on the web or iOS or goes the app management page in Google+ they will see an app name and image taken from the branding section of the API console project. If that branding doesn't fit the application they were using they might not trust the experience - in general, that's a pretty good smell that the applications should be in different projects.

App activity sources

If the user views their app activities, or those app activities are surfaced on Google, they will all appear to come from the same app (whatever is configured in the branding settings in the API console). If Match-3-tastic and FooPlayer are writing very different kinds of activities, that could be confusing.

Some ways of working around these issues:

Deep link application ordering

If a user has both FooPlayer Free and FooPlayer Pro installed, then a deep link might go to Free when it would be better to go to Pro. Apps can give a better experience here either by standardising the deep link handling in a library (so that there is no effective user experience difference), or by trampolining requests from one to another. It's relatively straightforward on both Android and iOS to see if another application is available, and to redirect the user to the preferred application if so. On Android this would just be firing off an Intent, while on iOS the app would use openUrl.

Sharing users across multiple application

If some applications are part of a different API console project, that doesn't mean they have to be totally separated. Most applications that implement Google+ sign-in also create a user in their own account management system, and associate the Google+ login with that account. This means the use of accounts can be separated from the project used to login with.

As an example, lets say Lets say we had 3 different games, each with their own project:

  • Match-3-tastic
  • Sparklefarmer
  • Battlefield of Combat (War Edition)

All three could talk to the same set of back-end services. If I sign in to Sparklefarmer with Google+, that can create a user account associated with my Google+ profile ID. If I then sign in to Battlefield of Combat, I can look up the account using the same profile ID, and simply mark that I am an active player for both games. That way I can still have a merged user account, but keep independent Google projects, and appropriate branding.

That said, what about seamless sign-in? That's a really nice feature, and if we're just using Google+ Sign-In for identity it would be great to have that flow across. Well, with Android we can actually do that, thanks to the magic of ID tokens.

If a user has signed in to Sparklefarmer, they have associated an account with their Google+ ID. When they log in to Battlefield of Combat on Android (and have granted the app the GET_ACCOUNTS permission, of course), we can retrieve ID tokens for each of the accounts on their device, which we can pass to the back end. These are cryptographically signed tokens which include the Google+ user ID, so we can check whether we have a user record in our shared backend, without having to have the user interact with us other than starting the app!

This will allow the user to be signed in to their shared game back end account, but wont sign them in to Google+. This is not so bad though: it can be a nice experience to have the app immediately recognise you, and then later prompt to connect Google+ to allow retrieving friends, writing app activities, or whatever other social features are needed.

The data in ID tokens, when stripped apart and decoded, look like this:

{
    "iss":"accounts.google.com",
    "sub":"113340090911954741696",
    "email":"notarealaddress@gmail.com",
    "aud":"366667191730-2djgro2rqr5ro230vio055gb8qr5h3ue.apps.googleusercontent.com",
    "iat":1373537811,
    "exp":1373541711
}

Note the "sub" value there - that's my Google+ ID. The "aud" is the client ID which it was granted for, and the the exp is a timestamp after which the token should no longer be used. Note that you should never try to verify these by hand, but use a client library instead - there's much more on this in Tim Bray's blog post on verifying calls to backends from Android apps.

To retrieve it, we'll need to grab the account names of any Google accounts on the device, which we will then fire off calls to the getToken method of GoogleAuthUtil.

To retrieve the token, we need a client ID for a server component created in the same API console project as your Android client ID - this will fill the 'aud' or audience field in the ID token, and you'll want to check that on the backend to make sure it was generated for app you expect (in our case: Battlefield of Combat). Because this can block, it must be done off the UI thread!

Note that you must send these tokens over HTTPS! Even though they can be verified as having been generated by Google, there's no way of telling them who actually sent them, so if they leak it is possible an attacker could do something naughty. They do have a limited lifetime, and all verification should including checking the expiry time, but it's best never to send them in the clear.

Popular posts from this blog

Client-Server Authentication with ID tokens

Common problems with Google+ Sign-In on Android

Upgrading Firebase.com & Using Google Sign In on Android