Join the Actions on Google Developer Challenge to win a trip to Google I/O 2018 and more than 20 other prizes.

Integrate with Google Using the OAuth 2.0 Authorization Code Flow

This document explains how to implement a minimal OAuth 2.0 server that supports the authorization code flow, sufficient for integrating your service with Google. The authorization code flow is the most secure of the supported flows, but requires some work to implement.

Overview

An OAuth 2.0 server implementation of the authorization code flow consists of two endpoints, which your service makes available by HTTPS. The first endpoint is the authorization endpoint, which is responsible for finding or obtaining consent from users for data access. The authorization endpoint presents sign-in UI to your users that aren't already signed in and records consent to the requested access. The second endpoint is the token exchange endpoint, which is used to exchange encrypted strings called tokens for different kinds of tokens. These tokens are passed to your service to access content.

When Google needs to call one of your service's APIs, Google uses these endpoints together to get permission from your users to call these APIs on their behalf. A typical OAuth 2.0 session initiated by Google has the following flow:

  1. First, Google opens your authorization endpoint in the user's browser. The user signs in if not signed in already, and grants Google permission to access their data with your API if they haven't already granted permission.
  2. Then, your service creates an authorization code and returns it to Google by redirecting the user's browser back to Google with the authorization code attached to the request.
  3. Next, Google sends the authorization code to your token exchange endpoint, which verifies the authenticity of the code and returns an access token and a refresh token. The access token is a short-lived token that your service accepts as credentials to access APIs. The refresh token is a long-lived token that Google can store and use to acquire new access tokens when they expire.
  4. Finally, Google calls your service's APIs, attaching the access token with each request. Your service verifies that the access token grants Google authorization to access the API, then completes the API call.

Before you begin

Before you add OAuth 2.0 authorization to your service, prepare the following information:

Endpoints

Decide what the URLs of your authorization endpoint and token exchange endpoint will be. For example, https://myservice.example.com/auth and https://oauth2.example.com/token. The authorization endpoint must accept user traffic, whereas the token exchange endpoint only needs to accept traffic from other servers (such as Google's). Note that these endpoints can be hosted on different domains.

Both endpoints must be accessible only over HTTPS; they must not accept plain HTTP requests.

Oftentimes an existing sign-in page can be adapted to serve as the authorization endpoint.

Client ID and client secret for Google

You must assign Google a client ID, which is used in OAuth 2.0 requests to identify the request's origin, and a client secret, which is used to prevent request forgery. The Google client ID and client secret can be any URL-safe string values of your choice. You must ensure that the client secret is visible to only Google and your service.

Token creation

OAuth 2.0 uses strings called tokens to communicate between the user agent, the client application, and the OAuth 2.0 server. There are three types of token that your server must create and use:

OAuth 2.0 tokens
Authorization code

A short-lived token that can be exchanged for a refresh token.

This code is very short-lived or limited to a single use for security purposes, since it is transmitted within a user agent and intended to be exchanged once for a long-lived token.

Access token

A token that grants the bearer access to a resource.

To limit exposure that could result from the loss of this token, it has a medium lifetime, usually expiring after an hour or so.

Refresh token

A long-lived token that can be exchanged for a new access token when an access token expires.

When your service is integrated with Google, this token is exclusively stored and used by Google. Google uses your server to exchange refresh tokens for access tokens, which are in turn used to access data.

OAuth 2.0 server implementations can define the format of the authorization codes, refresh tokens, and access tokens they use, based on the server's own requirements.

If you can store authorization state in a database, one way of implementing authorization codes, refresh tokens, and access tokens is as cryptographically secure random values, and using these random values as indexes to your authorization database.

A stateless way of implementing authorization codes, refresh tokens, and access tokens is as symmetrically-encrypted JSON objects. To encrypt and decrypt these tokens, you can use any symmetric encryption algorithm, such as AES and Blowfish. Using a high-level cryptography library such as NaCl, which has bindings for C, C++, and Python, or cryptography.io, can help simplify your implementation.

If you implement stateless tokens, whatever encryption algorithm you choose, the general encryption and decryption procedure looks like this:

  1. One time, generate a secret key and store it securely. You must keep this key secure to ensure that only your service can create tokens for itself.
  2. Create a JSON object with the token's information as described below.
  3. Encrypt the JSON object using your chosen encryption algorithm and secret key. The base64-encoded version of this encrypted object is your token.
  4. Later, you can decrypt the token using the same key.

Register your service

Each of your services must be registered by following the steps in Enabling Account Linking.

The key information that needs to be registered is:

  • Your service's OAuth 2.0 endpoint URLs
  • The Google client ID string and client secret key you want Google to use
  • Your Google API project ID, which you can find on the Settings page of the Google API Console.
  • The scopes, if any, that Google should request from your sign-in endpoint

Handle user sign-in

The first flow you must implement is the user sign-in flow. When Google needs to access your service's resources, Google sends the user to your authorization endpoint with a URL of the following form:

GET https://myservice.example.com/auth?client_id=GOOGLE_CLIENT_ID&redirect_uri=REDIRECT_URI&state=STATE_STRING&scope=REQUESTED_SCOPES&response_type=code

The sign-in request includes the following parameters:

Authorization endpoint parameters
client_id The Google client ID you registered with Google.
redirect_uri The URL to which to send the response to this request.
state A bookkeeping value that is passed back to Google unchanged in the redirect URI.
scope Optional: A space-delimited set of scope strings that specify the data Google is requesting authorization for.
response_type The string code.

Your authorization endpoint handles the sign-in request by doing the following:

  1. Verify that the client_id matches the Google client ID you registered with Google, and that the redirect_uri matches the redirect URL provided by Google for your service. These checks are important to prevent granting access to unintended or misconfigured client apps.

    If you support multiple OAuth 2.0 flows, also confirm that the response_type is code.

  2. Check if the user is signed in to your service. If the user isn't signed in, complete your service's sign-in or sign-up flow.

  3. After the user is signed in, if your service uses scopes to control access to specific resources, prompt the user for permission to access the scopes specified by the scope parameter.

  4. Generate an authorization code that Google will use to access your API. The authorization code can be any string value but it must uniquely represent the user, the client the token is for, and the code's expiration time, and it must not be guessable. You typically issue authorization codes that expire after around 10 minutes.

    A common way to implement authorization codes is to create a database record for each code granted, indexed by a cryptographically secure number, generated with 128 bits (16 bytes) of entropy, and to use the base64-encoded index number as the authorization code. For example, you might have an Authorizations table like the following:

    Index Type UserID ClientID ExpiresAt
    Y2RlZmdoaWprbG1ub3Bxcg== AUTH_CODE 1234 google 2016-11-08 16:20

    Another way to implement authorization codes is to create a JSON object containing the user ID, client ID, and expiration time. Then, encrypt the JSON object with a symmetric encryption algorithm such as AES and use the resulting string as the authorization code.

  5. Confirm that the URL specified by the redirect_uri parameter has the following form:

    https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID
    YOUR_PROJECT_ID is the ID found on the Settings page of the Google API Console, which you registered with Google.

  6. Redirect the user's browser to the URL specified by the redirect_uri parameter. Include the authorization token you just generated and the original, unmodified, state value when you redirect by appending the code and state parameters. For example, redirect the user to URL like the following:

    https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID?code=AUTHORIZATION_CODE&state=STATE_STRING

Google's OAuth 2.0 redirect handler will receive the authorization code, confirm that the state value hasn't changed, and then exchange the authorization code for access and refresh tokens using your service's token exchange endpoint.

Handle token exchange requests

Your service's token exchange endpoint is responsible for two kinds of token exchanges:

  • Exchanging authorization codes for access tokens and refresh tokens
  • Exchanging refresh tokens for access tokens

When a Google service needs to acquire a token from your service, it makes an HTTPS POST request to your token exchange endpoint. For example, to get a refresh token from an authorization code, Google makes a request like the following example:

POST /token HTTP/1.1
Host: oauth2.example.com
Content-Type: application/x-www-form-urlencoded

client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE

And, to get an access token from a refresh token, Google might make a request like the following example:

POST /token HTTP/1.1
Host: oauth2.example.com
Content-Type: application/x-www-form-urlencoded

client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET&grant_type=refresh_token&refresh_token=REFRESH_TOKEN

Token exchange requests include the following parameters:

Authorization endpoint parameters
client_id A string that identifies the request origin as Google. This string must be registered within your system as Google's unique identifier.
client_secret A secret string that you registered with Google for your service.
grant_type The type of token being exchanged. Either authorization_code or refresh_token.
code When grant_type=authorization_code, the code Google received from either your sign-in or token exchange endpoint.
refresh_token When grant_type=refresh_token, the refresh token Google received from your token exchange endpoint.

To exchange authorization codes for refresh tokens, and to exchange refresh tokens for access tokens, your token exchange endpoint responds to POST requests by doing the following:

  1. Verify that the client_id identifies the request origin as Google, and that the client_secret matches the expected value.
  2. Validate the authorization code or refresh token and generate a response:

    • If the grant type is authorization_code, do the following:

      1. If you implemented the authorization code as an index in a database, verify the index exists and then retrieve the authorization record.

        If you implemented the authorization code as an encrypted object, use the encryption method you chose to decode the authorization code.

      2. Verify that the token is not expired, and that the client ID specified in the request matches the client ID associated with the authorization code.

      3. Using the user ID from the authorization code, generate a refresh token and an access token. These tokens can be any string value but they must uniquely represent the user and the client the token is for, and they must not be guessable. For access tokens, also record the expiration time of the token (typically an hour after you issue the token). Refresh tokens do not expire.

        A common way to implement these tokens is to create a database record for each token granted, indexed by a cryptographically secure number, generated with 128 bits (16 bytes) of entropy, and to use the base64-encoded index number as the refresh token. For example, you might add records to your Authorizations table like the following:

        Index Type UserID ClientID ExpiresAt
        YWJjZGVmZ2hpamtsbW5vcA== ACCESS 1234 google 2016-11-08 16:20
        Index Type UserID ClientID ExpiresAt
        YmNkZWZnaGlqa2xtbm9wcQ== REFRESH 1234 google NULL

        Another way to implement tokens is to create a JSON object containing the user ID, client ID, token type, and, for access tokens, expiration time. Then, encrypt the JSON object with a symmetric encryption algorithm such as AES and use the resulting string as the token.

      4. Return the following JSON object in the body of the HTTPS response:

        {
          token_type: "bearer",
          access_token: "ACCESS_TOKEN",
          refresh_token: "REFRESH_TOKEN",
          expires_in: SECONDS_TO_EXPIRATION
        }
        

    • If the grant type is refresh_token, do the following:

      1. If you implemented the refresh token as an index in a database, verify the index exists and then retrieve the authorization record.

        If you implemented the refresh token as an encrypted object, use the encryption method you chose to decode the refresh token.

      2. Verify that the token is a refresh token and that the client ID specified in the request matches the client ID associated with the refresh token.

      3. If you store authorization state in a database, verify the user still has authorization.

      4. Using the user ID from the refresh token, generate an access token as described above. For example, if you use an Authorizations table, you might add a record like the following:

        Index Type UserID ClientID ExpiresAt
        YWJjZGVmZ2hpamtsbW5vcA== ACCESS 1234 google 2016-11-08 16:20
      5. Return the following JSON object in the body of the HTTPS response:

        {
          token_type: "bearer",
          access_token: "ACCESS_TOKEN",
          expires_in: SECONDS_TO_EXPIRATION
        }
        

After Google has obtained an access token for your service, Google will attach the access token to subsequent calls to your service's APIs.

Handle data access requests

Your service's API endpoints use the access token to identify the user on whose behalf Google is making the API call, and to verify that Google has authorization to access the endpoint on the user's behalf. For example, Google might make the following request to your service:

GET /mycontent HTTP/1.1
Host: myservice.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer ACCESS_TOKEN

In response, your endpoint does the following:

  1. If you implemented the access token as an encrypted object, use the encryption method you chose to decode the access token.

    If you implemented the access token as an index in a database, verify the index exists and then retrieve the authorization record.

  2. Verify that the value of the type field is access_token and that the token has not expired.

  3. If your service uses scopes to control access to specific resources, verify that one of the scopes listed in the decoded access token grants access to your endpoint.

  4. Use the user ID from the decoded token to respond to the request.

Your OAuth 2.0 implementation is now sufficient for integration with Google services.

Validate your implementation

You can validate your implementation by using the OAuth 2.0 Playground tool. In the tool, do the following steps:

  1. Click the gear icon to open the OAuth 2.0 Configuration window.
  2. In the OAuth Endpoints field, select Custom.
  3. Specify your OAuth 2.0 endpoints and the Google client ID and client secret in the corresponding fields.
  4. In the Step 1 section, don't select any Google scopes; instead, type a scope valid for your server, and click Authorize APIs.
  5. In the Step 2 and Step 3 sections, step through the OAuth 2.0 flow and verify that each step works as intended.