This reference page documents the API endpoints that your service must implement
to support Account Linking with Google. This includes [OAuth linking](https://developers.google.com/identity/account-linking/oauth-linking),
[Streamlined Account Linking](https://developers.google.com/identity/account-linking/oauth-with-sign-in-linking), and [App Flip](https://developers.google.com/identity/account-linking/app-flip-overview).

## Prerequisites and standards

To successfully implement these endpoints, your service must adhere to the
following standards:

- **OAuth 2.0** : Compliant with [RFC 6749](https://tools.ietf.org/html/rfc6749).
- **Token Revocation** : Compliant with [RFC 7009](https://tools.ietf.org/html/rfc7009).
- **JSON Web Tokens (JWT)** : Compliant with [RFC 7519](https://tools.ietf.org/html/rfc7519) (required for Streamlined Linking).
- **HTTPS**: All endpoints must be served over a secure HTTPS connection.

## Authorization Endpoint

The authorization endpoint is responsible for authenticating users and obtaining
their consent to link their accounts with Google.

- **URL:** Configured in the Actions Console or Google Cloud Console.
- **Method:** `GET`

### Request Parameters

| Parameters | Description |
|---|---|
| `client_id` | The client ID you assigned to Google. |
| `redirect_uri` | The URL to which you send the response to this request. |
| `state` | A bookkeeping value passed back to Google unchanged in the redirect URI. |
| `response_type` | Must be `code` for the authorization code flow. |
| `scope` | (Optional) Space-separated list of scopes for the data Google is requesting. |
| `user_locale` | (Optional) The Google Account language setting, specified using a [BCP-47](https://en.wikipedia.org/wiki/IETF_language_tag) language tag (e.g., `en-US`). |
| `code_challenge` | (Required for OAuth 2.1) The challenge derived from the code verifier. |
| `code_challenge_method` | (Optional) The method used to derive the challenge (e.g., `S256`). |

## Token Exchange Endpoint

This endpoint is responsible for exchanging authorization codes for tokens and
refreshing expired access tokens.

- **URL:** Configured in the Actions Console or Google Cloud Console.
- **Method:** `POST`
- **Content-Type:** `application/x-www-form-urlencoded`

### Exchange Authorization Code for Tokens

The following parameters are used in the initial token exchange request.

#### Request Parameters

| Parameters | Description |
|---|---|
| `client_id` | The client ID you assigned to Google. |
| `client_secret` | The client secret you assigned to Google. |
| `grant_type` | Must be `authorization_code`. |
| `code` | The authorization code received from the authorization endpoint. |
| `redirect_uri` | The same redirect URI used in the initial request. |
| `code_verifier` | (Required for PKCE) The original cryptographic random string. |

### Exchange Refresh Token for Access Token

The following parameters are used when refreshing an access token.

#### Request Parameters

| Parameters | Description |
|---|---|
| `client_id` | The client ID you assigned to Google. |
| `client_secret` | The client secret you assigned to Google. |
| `grant_type` | Must be `refresh_token`. |
| `refresh_token` | The refresh token previously issued to Google. |

### Response (JSON)

Return a successful response with a JSON object in the body of the HTTPS
response.

#### OpenAPI 3.1 Schema

    type: object
    required:
      - token_type
      - access_token
      - expires_in
    properties:
      token_type:
        type: string
        enum: [bearer]
      access_token:
        type: string
      refresh_token:
        type: string
      expires_in:
        type: integer

- **HTTP Status:** `200 OK`
- **Content-Type:** `application/json;charset=UTF-8`

| Fields | Description |
|---|---|
| `token_type` | **Required.** Must be `bearer`. |
| `access_token` | **Required.** A short-lived token used to access your service's APIs. |
| `refresh_token` | **Required for `authorization_code` `grant_type`.** A long-lived token used to obtain new access tokens. |
| `expires_in` | **Required.** The remaining lifetime of the access token in seconds. |

> [!NOTE]
> **Note:** You can optionally return a new `refresh_token` in your response when Google exchanges a refresh token for a new access token.

### Error Responses

If a request to the token endpoint fails, return an **HTTP 400 Bad Request**
error along with a JSON response containing the following fields:

- **HTTP Status:** `400 Bad Request`
- **Content-Type:** `application/json;charset=UTF-8`

| Error fields (JSON) | Description |
|---|---|
| `error` | **Required.** Must be `invalid_grant`. |
| `error_description` | (Optional) Human-readable text providing additional information. |

### Handle Streamlined Linking Intents

If your service supports [Streamlined Account Linking](https://developers.google.com/identity/account-linking/oauth-with-sign-in-linking) (OAuth with Sign in
with Google), your token exchange endpoint must additionally support JSON Web
Token (JWT) assertions and implement the required `check` and `get` intents,
and optionally the `create` intent.

> [!IMPORTANT]
> **Important:** These intents must be implemented in the same token exchange endpoint you use for basic OAuth linking. **Do not create a separate endpoint.**

The following parameters are used in these requests:

#### Request Parameters

| Parameters | Description |
|---|---|
| `intent` | The specific streamlined linking intent being requested: `check`, `get`, or optional `create`. |
| `grant_type` | For these requests, this parameter always has the value `urn:ietf:params:oauth:grant-type:jwt-bearer`. |
| `assertion` | A JSON Web Token (JWT) that provides a signed assertion of the Google user's identity. The JWT contains information that includes the user's Google Account ID, name, and email address. Your server **must** validate this JWT using the criteria listed in the [JWT Validation](https://developers.google.com/identity/account-linking/your-api-reference#jwt_validation) section. |
| `client_id` | The client ID you assigned to Google. |
| `client_secret` | The client secret you assigned to Google. |
| `scope` | **Optional:** Any scopes that you've configured Google to request from users. Usually present during `get` and `create` intents. |
| `response_type` | **Required for `create` intent:** Must be set to `token`. |

#### JWT Validation

To ensure the security of streamlined linking, your server must validate the
`assertion` (JWT) using the following criteria:

- **Signature** : Verify the signature against Google's public keys (available at [Google's JWK endpoint](https://www.googleapis.com/oauth2/v3/certs)).
- **Issuer (`iss`)** : Must be `https://accounts.google.com`.
- **Audience (`aud`)**: Must match the Google API Client ID assigned to your integration.
- **Expiration (`exp`)**: Must be in the future.

#### Response for `check` intent

A request with `intent=check` verifies whether the Google Account (identified by
the `sub` or `email` claim in the decoded JWT assertion) exists in your user
database.

- **HTTP Status:** `200 OK` (Account found) or `404 Not Found` (Account not found)
- **Content-Type:** `application/json;charset=UTF-8`

| Fields | Description |
|---|---|
| `account_found` | **Required.** `true` if the account exists, `false` otherwise. |

#### Response for `get` intent

A request with `intent=get` requests an access token for an existing Google
Account.

- **HTTP Status:** `200 OK`
- **Content-Type:** `application/json;charset=UTF-8`

The successful response JSON object uses the exact same structure as a
successful [standard Token Exchange response](https://developers.google.com/identity/account-linking/your-api-reference#response_json) (returning
`access_token`, `refresh_token`, etc.).

If the account cannot be linked, an HTTP 401 error is returned.

- **HTTP Status:** `401 Unauthorized`
- **Content-Type:** `application/json;charset=UTF-8`

| Error fields (JSON) | Description |
|---|---|
| `error` | **Required.** Must be `linking_error`. |
| `login_hint` | (Optional) The user's email address to pass to the fallback OAuth linking flow. |

#### Response for `create` intent (Optional)

The `create` intent is optional. If your service supports account creation using
Streamlined Linking, a request with `intent=create` initiates the creation of a
new user account with the information provided in the JWT.

- **HTTP Status:** `200 OK`
- **Content-Type:** `application/json;charset=UTF-8`

The successful response JSON object uses the exact same structure as a
successful [standard Token Exchange response](https://developers.google.com/identity/account-linking/your-api-reference#response_json) (returning
`access_token`, `refresh_token`, etc.).

If the user already exists, or if your service does not support account
creation, an HTTP 401 error is returned to prompt Google to fall back to the
standard OAuth linking flow.

- **HTTP Status:** `401 Unauthorized`
- **Content-Type:** `application/json;charset=UTF-8`

| Error fields (JSON) | Description |
|---|---|
| `error` | **Required.** Must be `linking_error`. |
| `login_hint` | The user's email address to pass to the fallback OAuth linking flow. |

*** ** * ** ***

## UserInfo Endpoint (Optional)

Used to retrieve basic profile information about the linked user, as specified
in the [OpenID Connect Core 1.0 specification](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo). This is required for features
like "Streamlined Linking" or "One Tap sign-in".

- **Method:** `GET`
- **Authentication:** `Authorization: Bearer ACCESS_TOKEN`

### Response (JSON)

Return a successful response with a JSON object in the body of the HTTPS
response.

- **HTTP Status:** `200 OK`
- **Content-Type:** `application/json;charset=UTF-8`

#### Response Fields

| Fields | Description |
|---|---|
| `sub` | **Required.** A unique ID that identifies the user in your system. |
| `email` | **Required.** The user's email address. |
| `email_verified` | **Required.** A boolean indicating whether the email address has been verified. |
| `given_name` | (Optional) The user's first name. |
| `family_name` | (Optional) The user's last name. |
| `name` | (Optional) The user's full name. |
| `picture` | (Optional) A URL to the user's profile picture. |

### Error Responses

If the access token is invalid or expired, return an **HTTP 401 Unauthorized**
error. You should also include the `WWW-Authenticate` response header.

Any unsuccessful response (4xx or 5xx) returned during the linking process is
considered non-recoverable. In these cases, Google will discard any retrieved
tokens, and the user must initiate the account linking process again.

## Token Revocation Endpoint (Optional)

Allows Google to notify your service when a user unlinks their account from the
Google surface. This endpoint must meet the requirements described in
[RFC 7009](https://tools.ietf.org/html/rfc7009).

- **Method:** `POST`
- **Content-Type:** `application/x-www-form-urlencoded`

### Request Parameters

| Parameters | Description |
|---|---|
| `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. |
| `token` | The token to be revoked. |
| `token_type_hint` | (Optional) A hint about the type of token being revoked, either `access_token` or `refresh_token`. If unspecified, defaults to `access_token`. |

> [!NOTE]
> **Note:** Due to their long lifetimes, typically only refresh tokens need to be revoked; short access token lifetimes often make their explicit revocation unnecessary.

### Responses

Return a successful response when the token is successfully deleted, or if the
token is already invalid.

- **HTTP Status:** `200 OK`
- **Content-Type:** `application/json;charset=UTF-8`

### Error Responses

If the token cannot be deleted for any reason (e.g. database unavailability),
return an **HTTP 503 error** . Google will retry the request later or as dictated
by the `Retry-After` header.

- **HTTP Status:** `503 Service Unavailable`
- **Content-Type:** `application/json;charset=UTF-8`
- **Headers:** `Retry-After: <HTTP-date / delay-seconds>`