--- title: Exchange a session token for an access token description: >- Learn about the token exchange grant type, the recommended way for embedded apps to acquire an access token, and how to exchange tokens manually. source_url: html: >- https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange md: >- https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange.md --- ExpandOn this page * [Requirements](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange.md#requirements) * [Step 1: Ensure you have a valid session token](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange.md#step-1-ensure-you-have-a-valid-session-token) * [Step 2: Get an access token](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange.md#step-2-get-an-access-token) * [Step 3: Make authenticated requests](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange.md#step-3-make-authenticated-requests) # Exchange a session token for an access token Tip You can use [Shopify CLI](https://shopify.dev/docs/apps/build/cli-for-apps) to generate a starter app with boilerplate code that handles authentication and authorization. The starter app includes code for an embedded app that uses [session tokens](https://shopify.dev/docs/apps/build/authentication-authorization/session-tokens) and [token exchange](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange). *** ## Requirements * You've created an embedded app that doesn't use a Shopify app template. * You have your app's [client credentials](https://shopify.dev/docs/apps/build/authentication-authorization/client-secrets). * You're familiar with [session tokens](https://shopify.dev/docs/apps/build/authentication-authorization/session-tokens) in Shopify. *** ## Step 1: Ensure you have a valid session token Your app's frontend must [acquire a session token from App Bridge](https://shopify.dev/docs/apps/build/authentication-authorization/session-tokens/set-up-session-tokens). In the current version of App Bridge, this is handled automatically using `authenticatedFetch`. You must include the token in the `AUTHORIZATION` header for all requests to the app's backend. Your app's backend is responsible for [authenticating](https://shopify.dev/docs/apps/build/authentication-authorization/session-tokens#request-flow-using-a-session-token) all incoming requests using the session token. *** ## Step 2: Get an access token If your app doesn't have a valid access token, then it can exchange its session token for an access token using [token exchange](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange). ### Token exchange API ```http POST https://{shop}.myshopify.com/admin/oauth/access_token ``` | Parameter | Description | | - | - | | `client_id`required | The API key for the app. | | `client_secret`required | The client secret for the app. | | `grant_type`required | The value `urn:ietf:params:oauth:grant-type:token-exchange` indicates that token exchange is to be performed. | | `subject_token`required | An ID token that represents the identity and active browser session of a merchant using the app. | | `subject_token_type`required | The value `urn:ietf:params:oauth:token-type:id_token` indicates that the subject token type is an ID token. | | `requested_token_type` | * `urn:shopify:params:oauth:token-type:offline-access-token` (default) for requesting [offline](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/offline-access-tokens) access tokens * `urn:shopify:params:oauth:token-type:online-access-token` for requesting [online](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/online-access-tokens) access tokens | | `expiring` | Only applicable if `requested_token_type` is set to `urn:shopify:params:oauth:token-type:offline-access-token`. Learn more about [expiring vs non-expiring offline tokens](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/offline-access-tokens#expiring-vs-non-expiring-offline-tokens)* `0` (default) for requesting a non-expiring offline token * `1` for requesting an expiring offline token | ### Example The following shows an example of a token exchange request and response for both an [online](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/online-access-tokens) and an [offline](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/offline-access-tokens) access token. ## Request ##### Online access token ```terminal curl -X POST \ https://{shop}.myshopify.com/admin/oauth/access_token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -H 'Accept: application/json' \ -d 'client_id={client_id}' \ -d 'client_secret={client_secret}' \ -d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \ -d 'subject_token={session_token}' \ -d 'subject_token_type=urn:ietf:params:oauth:token-type:id_token' \ -d 'requested_token_type=urn:shopify:params:oauth:token-type:online-access-token' ``` ##### Expiring offline access token ```terminal curl -X POST \ https://{shop}.myshopify.com/admin/oauth/access_token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -H 'Accept: application/json' \ -d 'client_id={client_id}' \ -d 'client_secret={client_secret}' \ -d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \ -d 'subject_token={session_token}' \ -d 'subject_token_type=urn:ietf:params:oauth:token-type:id_token' \ -d 'requested_token_type=urn:shopify:params:oauth:token-type:offline-access-token' \ -d 'expiring=1' ``` ##### Non-expiring offline access token ```terminal curl -X POST \ https://{shop}.myshopify.com/admin/oauth/access_token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -H 'Accept: application/json' \ -d 'client_id={client_id}' \ -d 'client_secret={client_secret}' \ -d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \ -d 'subject_token={session_token}' \ -d 'subject_token_type=urn:ietf:params:oauth:token-type:id_token' \ -d 'requested_token_type=urn:shopify:params:oauth:token-type:offline-access-token' ``` ## Response ##### Online access token ```json { "access_token": "f85632530bf277ec9ac6f649fc327f17", "scope": "write_orders,read_customers", "expires_in": 86399, "associated_user_scope": "write_orders", "associated_user": { "id": 902541635, "first_name": "John", "last_name": "Smith", "email": "john@example.com", "email_verified": true, "account_owner": true, "locale": "en", "collaborator": false } } ``` ##### Expiring offline access token ```json { "access_token": "f85632530bf277ec9ac6f649fc327f17", "scope": "write_orders,read_customers", "expires_in": 3600, "refresh_token": "shprt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "refresh_token_expires_in": 7776000 } ``` ##### Non-expiring offline access token ```json { "access_token": "f85632530bf277ec9ac6f649fc327f17", "scope": "write_orders,read_customers" } ``` If your session token is expired or otherwise invalid, then the token exchange request fails with an HTTP [status code](https://shopify.dev/docs/api/usage/response-codes) of `400 Bad Request`. ### Online access token response values | Value | Description | | - | - | | `access_token` | An API access token that can be used to access the shop’s data. Your app should store the token somewhere to make authenticated requests for a shop’s data. An [online access token](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/online-access-tokens) can be used for as long as the app is installed or for the next 24 hours, whichever comes first. After 24 hours, you need to refresh the access token. | | `scope` | The list of access scopes that were granted to your app and are associated with the access token. | | `expires_in` | The number of seconds until the access token expires. | | `associated_user_scope` | The list of access scopes that were granted to the app and are available for this access token, given the user’s permissions. | | `associated_user` | Information about the user who completed the authorization. The `email` field in this response appears regardless of the email verification status. If you’re using emails as an identification source, then make sure that the `email_verified` field is also `true`. You can use the `id` field to uniquely identify a single user. | ### Offline access token response values | Value | Description | | - | - | | `access_token` | An API access token that can be used to access the shop's data. Your app should store the token somewhere to make authenticated requests for a shop's data. Learn more about [offline access tokens](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/offline-access-tokens) and [online access tokens](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/online-access-tokens). | | `scope` | The list of access scopes that were granted to your app and are associated with the access token. | | `expires_in`\* | The number of seconds until the access token expires. | | `refresh_token`\* | The refresh token that can be used to obtain a new access token when the current one expires. | | `refresh_token_expires_in`\* | The number of seconds until the refresh token expires. | \* Only included when `expiring=1` is specified in the request. *** ## Step 3: Make authenticated requests After your app has obtained an API access token, it can make authenticated requests to the [GraphQL Admin API](https://shopify.dev/docs/api/admin-graphql) and fulfill incoming requests from the app frontend. The following example shows how to retrieve a list of products using the [GraphQL Admin API](https://shopify.dev/docs/api/admin-graphql). ## Terminal ```terminal curl -X POST \ https://{shop}.myshopify.com/admin/api/2025-10/graphql.json \ -H 'Content-Type: application/json' \ -H 'X-Shopify-Access-Token: {access_token}' \ -d '{ "query": "{ products(first: 5) { edges { node { id handle } } pageInfo { hasNextPage } } }" }' ``` *** * [Requirements](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange.md#requirements) * [Step 1: Ensure you have a valid session token](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange.md#step-1-ensure-you-have-a-valid-session-token) * [Step 2: Get an access token](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange.md#step-2-get-an-access-token) * [Step 3: Make authenticated requests](https://shopify.dev/docs/apps/build/authentication-authorization/access-tokens/token-exchange.md#step-3-make-authenticated-requests)