Skip to main content

Multipass grant

Shopify Plus

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.


  • 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.

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

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

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}
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.

ParameterRequiredDescription
grant_typeYesurn: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.
assertionYesThe Multipass token for the customer.
client_idYesThe client ID of your Headless or Hydrogen storefront.
client_secretConfidential clients onlyYour 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.


A successful exchange returns 200 with the access token:

{
"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, with the current version already filled in:

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.


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

StatuserrorCause
400invalid_assertionassertion 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.
400unsupported_grant_typeThe 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.
401invalid_clientclient_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.


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

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:

customerAccessTokenCreateWithMultipassMultipass grant
APIStorefront API mutationOAuth token endpoint
Token typeStorefront API customer access tokenCustomer Account API access token
Reads customer data fromStorefront APICustomer Account API
RenewalcustomerAccessTokenRenew mutationExchange a new Multipass token
Customer accounts versionClassicNew

The mutation keeps working for stores on classic customer accounts.



Was this page helpful?