Google Play services and OAuth Identity Tools

Posted by Tim Bray

The rollout of Google Play services to all Android 2.2+ devices worldwide is now complete, and all of those devices now have new tools for working with OAuth 2.0 tokens. This is an example of the kind of agility in rolling out new platform capabilities that Google Play services provides.

Why OAuth 2.0 Matters

The Internet already has too many usernames and passwords, and they don’t scale. Furthermore, your Android device has a strong notion of who you are. In this situation, the industry consensus is that OAuth 2.0 is a good choice for the job, offering the promise of strong security minus passwords.

Google Play services make OAuth 2.0 authorization available to Android apps that want to access Google APIs, with a good user experience and security.

Typically, when you want your Android app to use a Google account to access something, you have to pick which account on the device to use, then you have to generate an OAuth 2.0 token, then you have to use it in your HTTP-based dialogue with the resource provider.

These tasks are largely automated for you if you’re using a recent release of the Google APIs Client Library for Java; the discussion here applies if you want to access the machinery directly, for example in sending your own HTTP GETs and POSTs to a RESTful interface.

Preparation

Google Play services has just started rolling out, and even after the rollout is complete, will only be available on compatible Android devices running 2.2 or later. This is the vast majority, but there will be devices out there where it’s not available. It is also possible for a user to choose to disable the software.

For these reasons, before you can start making calls, you have to verify that Google Play services is installed. To do this, call isGooglePlayServicesAvailable(). The result codes, and how to deal with them, are documented in the ConnectionResult class.

Choosing an Account

This is not, and has never been, rocket science; there are many examples online that retrieve accounts from Android’s AccountManager and display some sort of pick list. The problem is that they all have their own look and feel, and for something like this, which touches on security, that’s a problem; the user has the right to expect consistency from the system.

Now you can use the handy AccountPicker.newChooseAccountIntent() method to give you an Intent; feed it to startActivityForResult() and you’ll launch a nice standardized user experience that will return you an account (if the user feels like providing one).

Two things to note: When you’re talking to these APIs, they require a Google account (AccountManager can handle multiple flavors), so specify GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE argument as the value for the allowableAccountTypes argument. Second, you don’t need an android.accounts.Account object, you just use the email-address string (available in account.name) that uniquely identifies it.

Getting a Token

There’s really only one method call you need to use, GoogleAuthUtil.getToken(). It takes three arguments: a Context, an email address, and another string argument called scope. Every information resource that is willing to talk OAuth 2.0 needs to publish which scope (or scopes) it uses. For example, to access the Google+ API, the scope is oauth2:https://www.googleapis.com/auth/plus.me. You can provide multiple space-separated scopes in one call and get a token that provides access to all of them. Code like this might be typical:

  private final static String G_PLUS_SCOPE = 
"oauth2:https://www.googleapis.com/auth/plus.me";
private final static String USERINFO_SCOPE =
"https://www.googleapis.com/auth/userinfo.profile";
private final static String SCOPES = G_PLUS_SCOPE + " " + USERINFO_SCOPE;

In an ideal world, getToken() would be synchronous, but three things keep it from being that simple:

  1. The first time an app asks for a token to access some resource, the system will need to interact with the user to make sure they’re OK with that.


  2. Any time you ask for a token, the system may well have a network conversation with the identity back-end services.


  3. The infrastructure that handles these requests may be heavily loaded and not able to get you your token right away. Rather than keeping you waiting, or just failing, it may ask you to go away and come back a little later.


The first consequence is obvious; you absolutely can’t call getToken() on the UI thread, since it’s subject to unpredictable delays.

When you call it, the following things can happen:

  • It returns a token. That means that everything went fine, the back-end thinks the authorization was successful, and you should be able to proceed and use the token.


  • It throws a UserRecoverableAuthException, which means that you need to interact with the user, most likely to ask for their approval on using their account for this purpose. The exception has a getIntent() method, whose return value you can feed to startActivityForResult() to take care of that. Of course, you’ll need to be watching for the OK in the onActivityResult() method.


  • It throws an IOException, which means that the authorization infrastructure is stressed, or there was a (not terribly uncommon on mobile devices) networking error. You shouldn’t give up instantly, because a repeat call might work. On the other hand, if you go back instantly and pester the server again, results are unlikely to be good. So you need to wait a bit; best practice would be the classic exponential-backoff pattern.


  • It throws a GoogleAuthException, which means that authorization just isn’t going to happen, and you need to let your user down politely. This can happen if an invalid scope was requested, or the account for the email address doesn’t actually exist on the device.


Here’s some sample code:

       try {
// if this returns, the OAuth framework thinks the token should be usable
String token = GoogleAuthUtil.getToken(this, mRequest.email(),
mRequest.scope());
response = doGet(token, this);

} catch (UserRecoverableAuthException userAuthEx) {
// This means that the app hasn't been authorized by the user for access
// to the scope, so we're going to have to fire off the (provided) Intent
// to arrange for that. But we only want to do this once. Multiple
// attempts probably mean the user said no.
if (!mSecondTry) {
startActivityForResult(userAuthEx.getIntent(), REQUEST_CODE);
response = null;
} else {
response = new Response(-1, null, "Multiple approval attempts");
}

} catch (IOException ioEx) {
// Something is stressed out; the auth servers are by definition
// high-traffic and you can't count on 100% success. But it would be
// bad to retry instantly, so back off
if (backoff.shouldRetry()) {
backoff.backoff();
response = authenticateAndGo(backoff);
} else {
response =
new Response(-1, null, "No response from authorization server.");
}

} catch (GoogleAuthException fatalAuthEx) {
Log.d(TAG, "Fatal Authorization Exception");
response = new Response(-1, null, "Fatal authorization exception: " +
fatalAuthEx.getLocalizedMessage());
}

This is from a sample library I’ve posted on code.google.com with an AuthorizedActivity class that implements this. We think that some of this authorization behavior is going to be app-specific, so it’s not clear that this exact AuthorizedActivity recipe is going to work for everyone; but it’s Apache2-licensed, so feel free to use any pieces that work for you. It’s set up as a library project, and there’s also a small sample app called G+ Snowflake that uses it to return some statistics about your Google+ posts; the app is in the Google Play Store and its source is online too.

Registering Your App

Most services that do OAuth 2.0 authorization want you to register your app, and Google’s are no exception. You need to visit the Google APIs Console, create a project, pick the APIs you want to access off the Services menu, and then hit the API Access tab to do the registration. It’ll want you to enter your package name; the value of the package attribute of the manifest element in your AndroidManifest.xml.

Also, it’ll want the SHA1 signature of the certificate you used to sign your app. Anyone who’s published apps to Google Play Apps knows about keystores and signing. But before you get there, you’ll be working with your debug-version apps, which are signed with a certificate living in ~/.android/debug.keystore (password: “android”). Fortunately, your computer probably already has a program called “keytool” installed; you can use this to get the signature. For your debug version, a correct incantation is:

keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -v -list

This will print out the SHA1 signature in a nicely labeled easy-to-cut-and-paste form.

This may feel a little klunky, but it’s worth it, because some magic is happening. When your app is registered and you generate a token and send it to a service provider, the provider can check with Google, which will confirm that yes, it issued that token, and give the package name of the app it was issued to. Those of you who who’ve done this sort of thing previously will be wondering about Client IDs and API Keys, but with this mechanism you don’t need them.

Using Your Token

Suppose you’ve registered your app and called GoogleAuthUtil.getToken() and received a token. For the purposes of this discussion, let’s suppose that it’s “MissassaugaParnassus42”. Then all you need to do is, when you send off an HTTP request to your service provider, include an HTTP header like so:

Authorization: Bearer MissassaugaParnassus42

Then your HTTP GETs and POSTs should Just Work. You should call GoogleAuthUtil.getToken() to get a token before each set of GETs or POSTs; it’s smart about caching things appropriately, and also about dealing with token expiry and refresh.

Once again, as I said at the top, if you’re happy using the Google APIs Client Library for Java, it’ll take care of all the client-side stuff; you’ll still need to do the developer console app registration.

Otherwise, there’s a little bit of coding investment here, but the payoff is pretty big: Secure, authenticated, authorized, service access with a good user experience.



Join the discussion on

+Android Developers



Google Play hits 25 billion downloads

Whether you’re looking for directions, checking email or sharing a picture with friends, apps are now an indispensable part of life. And if you’re using Android, it all starts with Google Play, home to 675,000 apps and games. That’s a lot of choice. We’ve now crossed 25 billion downloads from Google Play, and to celebrate we’re offering some great discounts for the next five days.


Every day you’ll be able to choose from a collection of apps from some of the world’s top developers including Gameloft, Electronic Arts, Rovio, runtastic, Full Fat and more. And all for just 25 cents. We’ll also be offering some special collections like 25 movies you must own, 25 banned books, 25 albums that changed the world and our 25 top selling magazines, all at special prices. Visit Google Play a little later today to check them out.

Twenty-five billion is more than twice the distance, in miles, that the Voyager 1 spacecraft has travelled since its launch 35 years ago. It’s the amount of time, in minutes, that have passed since some of our earliest ancestors began to set foot in Europe. And now, thanks to all of you, it’s a Google Play milestone. We look forward to the next 25 billion.

Posted by Jamie Rosenberg, Director, Digital Content

Turning the page with a new Google Play Books app for Android

Google Play Books enables you to read more than 4 million books on the go, and it's available in the U.S., Canada, Australia, Germany, Spain, Italy, France, Korea and Japan. Today we’re bringing new features to the Books app to help you better explore your books and understand what you’re reading.

Places and dictionary
School’s now in full swing and students are picking up the classics. Whether you're diving into Moby Dick or trying your hand at some Tolstoy, we want to make your reading experience as enjoyable and rewarding as possible. Starting today, when you come across an unfamiliar geographic location—a faraway city or distant mountain range—you can tap on the location to learn more about it. You’ll see an info card with a Google Map and the option to get more information by searching on Google or Wikipedia.

Explore locations using info cards in Turn Right at Machu Picchu: Rediscovering the Lost City One Step at a Time

Similarly when you come across an unfamiliar word (say, abligurition or jentacular), just tap it for a quick definition.

Translation
For those adventurous readers making their way through books in non-native languages, you can now easily translate words or phrases to and from a number of languages. Just select the text or word and use the button on the top action bar to indicate which language you’d like translate into.

Highlighting and notes
If you happen to page through any of the books on my shelf, you’ll likely find highlighted passages and illegibly scrawled notes in the margins. Starting today, our app lets you highlight text and easily take notes. And because all your books live in the cloud, highlights and notes sync on your tablet, phone and the web.


You will also notice a new sepia reading theme (in addition to the current day and night themes), 2D sliding page turn animation, and lots of stability improvements. Finally, you can now read Japanese books in a vertical, right-to-left layout—and flip pages from right to left.

We hope these features make reading more enjoyable—and productive.

Posted by Xinxing Gu, Product Manager, Google Play

The Benefits & Importance of Compatibility

We built Android to be an open source mobile platform freely available to anyone wishing to use it. In 2008, Android was released under the Apache open source license and we continue to develop and innovate the platform under the same open source license -- it is available to everyone at: http://source.android.com. This openness allows device manufacturers to customize Android and enable new user experiences, driving innovation and consumer choice.

As the lead developer and shepherd of the open platform, we realize that we have a responsibility to app developers -- those who invested in the platform by adopting it and building applications specifically for Android. These developers each contribute to making the platform better -- because when developers support a platform with their applications, the platform becomes better and more attractive to consumers. As more developers build great apps for Android, more consumers are likely to buy Android devices because of the availability of great software content (app titles like Fruit Ninja or Google Maps). As more delighted consumers adopt Android phones and tablets, it creates a larger audience for app developers to sell more apps. The result is a strategy that is good for developers (they sell more apps), good for device manufacturers (they sell more devices) and good for consumers (they get more features and innovation).

In biological terms, this is sometimes referred to as an ecosystem. In economic terms, this is known as a virtuous cycle -- a set of events that reinforces itself through a feedback loop. Each iteration of the cycle positively reinforces the previous one. These cycles will continue in the direction of their momentum until an external factor intervenes and breaks the cycle.

When we first contemplated Android and formed the Open Handset Alliance, we wanted to create an open virtuous cycle where all members of the ecosystem would benefit. We thought hard about what types of external factors could intervene to weaken the ecosystem as a whole. One important external factor we knew could do this was incompatibilities between implementations of Android. Let me explain:

Imagine a hypothetical situation where the platform on each phone sold was just a little bit different. Different enough where Google Maps would run normally on one phone but run terribly slow on another. Let's say, for sake of example, that Android implemented an API that put the phone to sleep for a fraction of a second to conserve battery life when nothing was moving on the screen. The API prototype for such a function might look like SystemClock.sleep(millis) where the parameter "millis" is the number of milliseconds to put the device to sleep for.

If one phone manufacturer implemented SystemClock.sleep() incorrectly, and interpreted the parameter as Seconds instead of Milliseconds, the phone would be put to sleep a thousand times longer than intended! This manufacturer’s phone would have a terrible time running Google Maps. If apps don’t run well across devices due to incompatibilities, consumers would leave the ecosystem, followed by developers. The end of the virtuous cycle.

We have never believed in a “one size fits all” strategy, so we found a way to enable differentiation for device manufactures while protecting developers and consumers from incompatibilities by offering a free "compatibility test suite" (CTS). CTS is a set of software tools that tests and exercises the platform to make sure that (for example) SystemClock.sleep(millis) actually puts the device to sleep for only milliseconds. Like Android, the test suite is freely available to everyone under the Apache open source license: http://source.android.com/compatibility/cts-intro.html 

While Android remains free for anyone to use as they would like, only Android compatible devices benefit from the full Android ecosystem. By joining the Open Handset Alliance, each member contributes to and builds one Android platform -- not a bunch of incompatible versions. We’re grateful to the over 85 Open Handset Alliance members who have helped us build the Android ecosystem and continue to drive innovation at an incredible pace. Thanks to their support the Android ecosystem now has over 500 million Android-compatible devices and counting!

Posted by Andy Rubin, Senior Vice President of Mobile and Digital Content