Multipass grant
Multipass is available only to stores on the Shopify Plus plan that were already using it, and is no longer available to new stores. For the full availability rules, refer to Multipass.
Multipass is available only to stores on the Shopify Plus plan that were already using it, and is no longer available to new stores. For the full availability rules, refer to Multipass.
The Multipass grant exchanges a Multipass token for a Customer Account API 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.
Anchor to RequirementsRequirements
- Your store meets the 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 for the token format and example implementations.
Anchor to How it worksHow it works
- Your app authenticates the customer with your existing sign-in system. That authentication is outside the scope of this grant.
- Your backend generates a Multipass token for the customer, using the same token generation steps as URL sign-in.
- Your client posts the token to the store's token endpoint as the
assertionparameter of the Multipass grant. - Shopify identifies your client, confirms the store can use Multipass, and decrypts and verifies the token with the store's Multipass secret.
- Shopify finds the customer from the token's
emailclaim, or creates a customer record if none matches, and returns a Customer Account API access token.
Anchor to Exchange a Multipass tokenExchange 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 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
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
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.
Anchor to ResponseResponse
A successful exchange returns 200 with the access token:
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, with the current version already filled in:
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.
Anchor to ErrorsErrors
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.
Anchor to Log outLog out
Use backchannel logout 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.
Anchor to Migrate from ,[object Object]Migrate from customerAccessTokenCreateWithMultipass
customerAccessTokenCreateWithMultipassThe 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 | Customer Account API |
| Renewal | customerAccessTokenRenew mutation | Exchange a new Multipass token |
| Customer accounts version | Classic | New |
The mutation keeps working for stores on classic customer accounts.