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:

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.

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.

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.

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.

Optional: Scope strings

Depending on how much and what kind of user data your API makes available,
you might want to define scopes that represent different categories of user
data. By doing so, parties can ask permission from your users to access only
certain kinds of data, and restrict the data available to clients to only the
authorized scopes.

In particular, if your service makes more data available than necessary for
integration with Google, you might use scopes to grant access to only some of
the data.

For example, if your service provides access to your users' profiles and
wish lists, you might define the following scopes:

Example scopes

profile

View the user's basic profile information

wish_list_read

View the user's wish list

wish_list_readwrite

View and add items to the user's wish list

If your service uses OAuth 2.0 to grant API access to only one other party,
such as Google, or if your service makes only one narrow category of data
available, you might choose to define only one scope, or not to define any
scopes.

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:

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.

Create a JSON object with the token's information as described below.

Encrypt the JSON object using your chosen encryption algorithm and secret
key. The base64-encoded version of this encrypted object is your token.

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.

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.

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.

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.

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.

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:

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:

Verify that the client_id identifies the request origin as
Google, and that the client_secret matches the expected
value.

Validate the authorization code or refresh token and generate a
response:

If the grant type is authorization_code, do the
following:

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.

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.

If you cannot verify all of the above criteria, return an HTTP
400 Bad Request error with {"error": "invalid_grant"}
as the body.

Otherwise, 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.

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: