---
title: Multipass grant
description: >-
  Exchange a Multipass token for a Customer Account API access token with the
  Multipass OAuth grant.
source_url:
  html: 'https://shopify.dev/docs/api/customer-authentication/multipass-grant'
  md: 'https://shopify.dev/docs/api/customer-authentication/multipass-grant.md'
api_name: customer
---

# Multipass grant

**Shopify Plus:**

Multipass is available only to stores on the [Shopify Plus](https://www.shopify.com/plus) plan that were already using it, and is no longer available to new stores. For the full availability rules, refer to [Multipass](https://shopify.dev/docs/api/customer-authentication/multipass#requirements).

The Multipass grant exchanges a [Multipass token](https://shopify.dev/docs/api/customer-authentication/multipass) for a [Customer Account API](https://shopify.dev/docs/api/customer) access token. Your backend already knows who the customer is. Instead of sending them through a login screen, sign a Multipass token and trade it for an access token at the store's token endpoint.

The grant is an OAuth assertion grant, with the Multipass token as the assertion. Shopify defines the token format. Keep generating tokens exactly as you do today.

***

## Requirements

* Your store meets the [Multipass requirements](https://shopify.dev/docs/api/customer-authentication/multipass#requirements) and uses new customer accounts.
* The client making the request is a Headless or Hydrogen storefront with the Customer Account API configured.
* You can generate Multipass tokens. Refer to [Multipass](https://shopify.dev/docs/api/customer-authentication/multipass) for the token format and example implementations.

***

## How it works

1. Your app authenticates the customer with your existing sign-in system. That authentication is outside the scope of this grant.
2. Your backend generates a Multipass token for the customer, using the same [token generation steps](https://shopify.dev/docs/api/customer-authentication/multipass#step-2-encode-your-customer-information-using-json) as URL sign-in.
3. Your client posts the token to the store's token endpoint as the `assertion` parameter of the Multipass grant.
4. Shopify identifies your client, confirms the store can use Multipass, and decrypts and verifies the token with the store's Multipass secret.
5. Shopify finds the customer from the token's `email` claim, or creates a customer record if none matches, and returns a Customer Account API access token.

***

## Exchange a Multipass token

Post the grant to the store's token endpoint, `https://{shop_domain}/authentication/oauth/token`, as a form-encoded request body. The endpoint is also published as `token_endpoint` in the store's [OpenID Connect configuration](https://shopify.dev/docs/api/customer#discover-authentication-endpoints) if you prefer to discover it. Confidential clients authenticate the request with HTTP Basic credentials. Call the token endpoint from a backend, never from a browser or a mobile client.

## Grant request

##### Public client

```text
POST https://{shop_domain}/authentication/oauth/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json

grant_type=urn:shopify:params:oauth:grant-type:multipass&client_id={client_id}&assertion={multipass_token}
```

##### Confidential client

```text
POST https://{shop_domain}/authentication/oauth/token
Authorization: Basic base64({client_id}:{client_secret})
Content-Type: application/x-www-form-urlencoded
Accept: application/json

grant_type=urn:shopify:params:oauth:grant-type:multipass&client_id={client_id}&assertion={multipass_token}
```

The request body is a single form-encoded line. It's shown unwrapped for a reason: a literal newline before a `&` becomes part of the preceding parameter's value, and the grant type is compared exactly. A wrapped copy is rejected.

| Parameter | Required | Description |
| - | - | - |
| `grant_type` | Yes | `urn:shopify:params:oauth:grant-type:multipass`. Send it in the request body. Shopify doesn't run the grant when `grant_type` arrives as a query parameter. |
| `assertion` | Yes | The Multipass token for the customer. |
| `client_id` | Yes | The client ID of your Headless or Hydrogen storefront. |
| `client_secret` | Confidential clients only | Your storefront's client secret. Prefer the `Authorization: Basic` header. A public client that sends a `client_secret` is rejected with `invalid_client`. |

There's no `scope` parameter. The access token carries the scopes configured on your storefront.

***

## Response

A successful exchange returns `200` with the access token:

```json
{
  "access_token": "{access_token}",
  "token_type": "bearer",
  "expires_in": 3600
}
```

Pass the access token in the `Authorization` header of your Customer Account API requests, with no `Bearer` prefix. The GraphQL endpoint is also published as `graphql_api` in the store's [API configuration](https://shopify.dev/docs/api/customer#discover-api-endpoints), with the current version already filled in:

```bash
curl -X POST https://{shop_domain}/customer/api/{api_version}/graphql \
  -H 'Content-Type: application/json' \
  -H 'Authorization: {access_token}' \
  -d '{"query": "{ customer { firstName lastName } }"}'
```

A few things to know about the token:

* The response contains no refresh token. When the access token expires, generate a new Multipass token and exchange it again.
* The response is sent with `Cache-Control: no-store`. Don't cache or log the token.
* Shopify records that the session was authenticated through Multipass. Checkout uses that to treat it differently from a session that started with a password or an OpenID Connect sign-in.

One difference affects your checkout flow: buyers in a Multipass session are asked to confirm the card security code (CVV) before paying with a saved credit card. Refer to [Saved payment methods in checkout](https://shopify.dev/docs/api/customer-authentication/multipass#saved-payment-methods-in-checkout).

***

## Errors

Errors follow the OAuth error format, with the reason in the `error` field:

| Status | `error` | Cause |
| - | - | - |
| `400` | `invalid_assertion` | `assertion` is missing, or the Multipass token can't be decrypted or verified with the store's secret, has a malformed payload, or has already been redeemed. |
| `400` | `unsupported_grant_type` | The store can't use the Multipass grant. Multipass isn't enabled or has no secret configured, or the client isn't a Headless or Hydrogen storefront. |
| `401` | `invalid_client` | `client_id` is unknown, a confidential client's credentials are missing or wrong, or a public client sent a `client_secret`. |

Shopify returns the same `invalid_assertion` error for every token failure. The response never reveals why a token was rejected. Log the request on your side to tell a signing problem from an expired token.

The token endpoint is also rate limited. Too many bearer-grant token requests from one store in a rolling minute get a `429`. The count covers the Multipass grant and the JWT bearer grant together, per store, and doesn't include authorization code or refresh token requests. A `429` isn't an OAuth error and usually carries no response body. Handle it before you try to parse one, and retry with backoff rather than treating it as a failed exchange.

Each Multipass token can be redeemed once, and the check is shared across surfaces. A token you've already redeemed on the online store can't be redeemed again through this grant, and the reverse is also true. Generate a token when you need it rather than in advance.

***

## Log out

Use [backchannel logout](https://shopify.dev/docs/api/customer-authentication/multipass#log-customers-out) to end a session created through this grant. It also revokes the access tokens the grant issued, which stop working immediately rather than lasting out their hour.

***

## Migrate from `customerAccessTokenCreateWithMultipass`

The Storefront API mutation and the Multipass grant both take a Multipass token and return an access token for the customer it identifies. The two access tokens aren't interchangeable:

| | `customerAccessTokenCreateWithMultipass` | Multipass grant |
| - | - | - |
| API | Storefront API mutation | OAuth token endpoint |
| Token type | Storefront API customer access token | Customer Account API access token |
| Reads customer data from | [Storefront API](https://shopify.dev/docs/api/storefront) | [Customer Account API](https://shopify.dev/docs/api/customer) |
| Renewal | `customerAccessTokenRenew` mutation | Exchange a new Multipass token |
| Customer accounts version | Classic | New |

The mutation keeps working for stores on classic customer accounts.

***

## Related

[Multipass\
\
](https://shopify.dev/docs/api/customer-authentication/multipass)

[Generate Multipass tokens, sign customers in from a URL, and log them out](https://shopify.dev/docs/api/customer-authentication/multipass)

[Customer Account API\
\
](https://shopify.dev/docs/api/customer)

[Query and update customer data with the Customer Account API](https://shopify.dev/docs/api/customer)

[Authenticate buyers in checkout\
\
](https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/checkout-authentication)

[Carry an authenticated buyer from your headless storefront into checkout](https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/checkout-authentication)

***
