Google Accounts Authentication and Authorization

Cross-client Identity

When developers build software, it routinely includes modules that run on a web server, other modules that run in the browser, and others that run as native mobile apps. Both developers and the people who use their software typically think of all these modules as part of a single app.

Google’s OAuth 2.0 implementation supports this view of the world. To use any of the OAuth2.0-based services, you must set up your software in the Google Developers Console. The unit of organization in the Developers Console is a "project," which can correspond to a multi-component app. For each project, you can provide branding information, and you must specify which APIs the app will access. Each component of a multi-component app is identified by a client ID, a unique string that is generated in the Developers Console.

Cross-client authorization goals

When an app uses OAuth 2.0 for authorization, the app acts on a user's behalf to request an OAuth 2.0 access token for access to a resource, which the app identifies by one or more scope strings. Normally, the user is asked to approve the access.

When a user grants access to your app for a particular scope, the user is looking at the user consent screen, which includes project-level product branding that you set up in the Google Developers Console. (For information about setting up the consent screen, see Setting up OAuth 2.0 in the Developers Console help.) Therefore, Google considers that when a user has granted access to a particular scope to any client ID in a project, the grant indicates the user's trust in the whole application for that scope.

The effect is that the user should not be prompted to approve access to any resource more than once for the same logical application, whenever the components of the application can be reliably authenticated by Google's authorization infrastructure, which today includes web clients, JavaScript clients, and Android apps.

Cross-client access tokens

Software can obtain OAuth 2.0 Access tokens in a variety of ways, depending on the platform where the code is running. For details, see Using OAuth 2.0 to Access Google APIs and Google Play Services Authorization. Normally, user approval is required when granting an access token.

Fortunately, the Google authorization infrastructure can use information about user approvals for a client ID within a given project when evaluating whether to authorize others in the same project.

The effect is that if an Android app requests an access token for a particular scope, and the requesting user has already granted approval to a web component in the same project for that same scope, the user will not be asked once again to approve. This works both ways: If access to a scope has been granted on Android, it will not be demanded again from a web component.

Android ID tokens

One benefit of cross-client identity is that you can leverage it and ID tokens to enable Android apps to talk to their home server without requiring the user to log in.

Example

Suppose that there is a project set up in the Developers Console that contains a server-side component (an app) whose client ID is 9414861317621.apps.googleusercontent.com. Suppose that there is also a native Android app in the same project.

The Android app can call the GoogleAuthUtil.getToken() method on behalf of any of the Google accounts on the device, and with a scope argument value of audience:server:client_id:9414861317621.apps.googleusercontent.com. The prefix audience:server:client_id: is fixed, and the rest of the scope string is the client ID of the web component.

In this scenario, GoogleAuthUtil will observe that the Android app and the web client ID are in the same project, and without user approval, return an ID token to the app, signed by Google. The ID token will contain several data fields, of which the following are particularly relevant:

  • iss: always accounts.google.com

  • aud: the client ID of the web component of the project

  • azp: the client ID of the Android app component of project

  • email: the email that identifies the user requesting the token

This ID token is designed to be transmitted to the web module over HTTPS. Before using it, the web component must do the following:

  1. Validate the cryptographic signature. Because the token takes the form of a JSON web token or JWT and there are libraries to validate JWTs available in most popular programming languages, this is straightforward and efficient.

  2. Ensure that the value of the aud field is identical to its own client ID.

Once this is accomplished, the web component can have a high degree of certainty that:

  • The token was issued by Google.

  • The token was sent to a device that was being operated by the person identified in the payload's email field.

The web component can also have good confidence that the token was obtained by the Android app identified by the client ID in the payload’s azp field. However, non-compatible or rooted Android devices might be able to fake the azp value.

The effect is that the web component can treat the data coming from the Android client, along with the ID token, as coming from a signed-in user of the project, and act confidently on that user’s behalf to access and update that user’s data, without redundantly prompting for authentication.

Android app obtains offline access for web back-end

Suppose once again that a project includes a web component whose client ID is 9414861317621.apps.googleusercontent.com, and in this case wants to access two different resources on behalf of a user, and to do so even when the user is not online. However, the software is normally accessed interactively through an Android app. Let us further suppose that the resources are identified by the Google Drive scope string https://www.googleapis.com/auth/drive.file and the Google+ scope login string https://www.googleapis.com/auth/plus.login, which we'll refer to as resource-1 and resource-2.

In this situation, an Android app that is in the same Developers Console project as the web component can call the GoogleAuthUtil.getToken() method, specifying any of the Google accounts on the device, and with a scope argument value of oauth2:server:client_id:9414861317621.apps.googleusercontent.com:api_scope:resource-1 resource-2.

In this case, GoogleAuthUtil.getToken() will first require that the user has authorized this project for access to the two scopes. Assuming this is OK, the method will return not an OAuth token, but a short-lived authorization code, which can be exchanged for an access token and a refresh token.

The Android app can then send the authorization code to its web component using HTTPS. The web component can exchange the code, as described in Handling the response, for an access token and a refresh token. The following rules apply to the web component:

  • When the web component exchanges the code for tokens, it should not include the redirect_uri argument in the POST request.

  • When the web component receives the tokens, it must examine the ID token. Signature-checking is not required, since the token was received from Google over a secure channel. However, the web component must:

    • Verify that the aud field in the ID token from Google is identical to its client ID from the Google Developers Console.

    • Verify that the sub field in the ID token from Google is identical to the sub field in the ID token that it received from the client.

  • Since the refresh token does not expire, it is the responsibility of the web component to store the refresh token in a secure and long-lived manner.

  • It is important that the Android app never attempt to exchange the code for a refresh token on its own. This would require that the app store the server's client ID and client secret. Including these in your Android app is insecure, because apps can be easily decomposed.

You can use the access token to access the required scopes for a short period of time, on the order of an hour. The refresh token does not expire unless explicitly revoked, and you can use it to obtain new access tokens at any time.

Recommended flow

To use resources efficiently and avoid redundant work, we recommend the following application flow when an Android app commences a session of work with its web back-end:

  1. Use HTTP POST requests for all requests to the server, and include an ID token in the body of each POST request. The ID token, which you acquire as described in the preceding section, informs the back-end of the user's identity.

  2. In the first request of a session, also include a query to the back-end as to whether it has the appropriate level of online access to the needed scopes.

  3. The web back-end must maintain knowledge of whether it has a working refresh token. If it doesn’t have a refresh token or discovers that its refresh token it has been revoked (which you can easily test by using the refresh token to fetch a new access token), the web back-end communicates its lack of a refresh token to the client.

  4. If the client receives a message from its back-end indicating that the back-end does not have a working refresh token, the Android app obtains an authorization code, as described above, and transmits the code to its back-end.

  5. The client and server proceed with their session.

In this sequence, control over the request for offline access is maintained by the server-side code, which is best positioned to know when offline access is needed. Also, if the app always requested a refresh token without checking whether the server already had one, this would eventually exhaust the finite number of refresh tokens that can be outstanding for a user/app combination.

The effect of all this is that the mobile-app component of a project can be used to obtain permanent offline access to resources for other components, with only the minimum number of approvals from the user.

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.