--- title: Session Token API description: >- The Session Token API lets you authenticate requests from your extension to your app's backend using a signed JSON Web Token (JWT). Use this API to get a token that your backend can verify using your app's shared secret, confirming the request came from a legitimate Shopify extension. api_version: 2025-07 api_name: customer-account-ui-extensions source_url: html: >- https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/target-apis/platform-apis/session-token-api md: >- https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/target-apis/platform-apis/session-token-api.md --- Migrate to Polaris Version 2025-07 is the last API version to support React-based UI components. Later versions use [web components](https://shopify.dev/docs/api/customer-account-ui-extensions/latest/polaris-web-components), native UI elements with built-in accessibility, better performance, and consistent styling with [Shopify's design system](https://shopify.dev/docs/apps/design). Check out the [migration guide](https://shopify.dev/docs/apps/build/customer-accounts/migrate-to-web-components) to upgrade your extension. # Session Token API The Session Token API lets you authenticate requests from your extension to your app's backend using a signed [JSON Web Token (JWT)](https://jwt.io/introduction). Use this API to get a token that your backend can verify using your app's shared secret, confirming the request came from a legitimate Shopify extension. ### Use cases * **Authenticate backend requests**: Pass a session token as a Bearer token in API calls to your app's backend so you can verify the request came from your extension. * **Identify the customer**: Read the optional `sub` claim in the token to get the customer's GID when they're signed in and your app has [access to protected customer data](https://shopify.dev/docs/apps/store/data-protection/protected-customer-data). * **Verify the shop**: Use the `dest` claim to confirm which shop the request is associated with, ensuring your backend responds with the correct data. ### Support Targets (25) ### Supported targets * Customer​Account::Kitchen​Sink * [customer-account.​footer.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/footer#footer-render-after-) * [customer-account.​order-index.​announcement.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-index#order-index-targets) * [customer-account.​order-index.​block.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-index#order-index-block-) * [customer-account.​order-status.​announcement.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#order-status-announcement-) * [customer-account.​order-status.​block.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#order-status-block-) * [customer-account.​order-status.​cart-line-item.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#cart-line-item-render-after-) * [customer-account.​order-status.​cart-line-list.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#cart-line-list-render-after-) * [customer-account.​order-status.​customer-information.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-status#customer-information-render-after-) * [customer-account.​order-status.​fulfillment-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/fulfillment-status#fulfillment-status-targets) * [customer-account.​order-status.​payment-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/payments-and-returns#payments-and-returns-targets) * [customer-account.​order-status.​return-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/payments-and-returns#return-details-render-after-) * [customer-account.​order-status.​unfulfilled-items.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/fulfillment-status#unfulfilled-items-render-after-) * [customer-account.​order.​action.​menu-item.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-actions#order-action-menu-item-) * [customer-account.​order.​action.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/order-actions#order-action-) * [customer-account.​order.​page.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/full-page#order-specific-full-page-) * [customer-account.​page.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/full-page#customer-account-full-page-) * [customer-account.​profile.​addresses.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-default#profile-page-default-targets-) * [customer-account.​profile.​announcement.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-default#announcement-) * [customer-account.​profile.​block.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-default#profile-block-) * [customer-account.​profile.​company-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#profile-page-b2b-targets-) * [customer-account.​profile.​company-location-addresses.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#company-location-addresses-render-after-) * [customer-account.​profile.​company-location-payment.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#company-location-payment-render-after-) * [customer-account.​profile.​company-location-staff.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/targets/profile-page-b2b#company-location-staff-render-after-) * customer-account.​profile.​payment.​render-after ### Properties The Session Token API object provides session token functionality for customer account extensions. Access the following properties on the API object to retrieve signed tokens for authenticating requests to your app's backend. * **sessionToken** **SessionToken** **required** Provides access to session tokens for verifying requests from your extension to your app's backend. Session tokens are signed [JSON Web Tokens (JWTs)](https://jwt.io/) that contain information about the current session. For more details, see the [Session Token API](https://shopify.dev/docs/api/customer-account-ui-extensions/2025-07/apis/session-token). ### SessionToken Provides access to session tokens for verifying requests from your extension to your app's backend. Session tokens are signed \[JSON Web Tokens (JWTs)]\(https://jwt.io/) that contain information about the current session. For more details, see the \[Session Token API]\(/docs/api/customer-account-ui-extensions/2025-07/apis/session-token). * get Requests a session token that hasn't expired. Call this method every time you need to make a request to your backend to get a valid token. Returns cached tokens when possible, so you don't need to store tokens yourself. ```ts () => Promise ``` Examples ### Examples * #### Fetch data with a session token ##### Description Retrieve a session token and pass it as a Bearer token to authenticate a request to your app's backend. This example uses \`shopify.sessionToken.get()\` to obtain the token and includes it in the \`Authorization\` header of a fetch call. ##### React ```tsx import {useEffect} from 'react'; import { reactExtension, Banner, useApi, } from '@shopify/ui-extensions-react/customer-account'; export default reactExtension( 'customer-account.order-status.block.render', () => , ); function Extension() { const {sessionToken} = useApi(); useEffect(() => { async function queryApi() { // Request a new (or cached) session token from Shopify const token = await sessionToken.get(); console.log('sessionToken.get()', token); const apiResponse = await fetchWithToken(token); // Use your response console.log('API response', apiResponse); } function fetchWithToken(token) { const result = fetch( 'https://myapp.com/api/session-token', { headers: { Authorization: `Bearer ${token}`, }, }, ); return result; } queryApi(); }, [sessionToken]); return ( See console for API response ); } ``` ##### TS ```js import { extension, Banner, } from '@shopify/ui-extensions/customer-account'; export default extension( 'customer-account.order-status.block.render', (root, {sessionToken}) => { async function queryApi() { // Request a new (or cached) session token from Shopify const token = await sessionToken.get(); console.log('sessionToken.get()', token); const apiResponse = await fetchWithToken(token); // Use your response console.log('API response', apiResponse); } function fetchWithToken(token) { const result = fetch( 'https://myapp.com/api/session-token', { headers: { Authorization: `Bearer ${token}`, }, }, ); return result; } queryApi(); root.appendChild( root.createComponent( Banner, {}, 'See console for API response', ), ); }, ); ``` * #### ##### Description Review the structure of a decoded session token to understand the available claims. This example shows the JSON payload including the \`dest\`, \`aud\`, \`exp\`, and optional \`sub\` claims. ##### Session token claims ```json { // Shopify URL "dest": "store-name.myshopify.com", // The Client ID of your app "aud": "", // When the token expires. Set at 5 minutes. "exp": 1679954053, // When the token was actived "nbf": 1679953753, // When the token was issued "iat": 1679953753, // A unique identifier (a nonce) to prevent replay attacks "jti": "6c992878-dbaf-48d1-bb9d-6d9b59814fd1", // Optional claim present when a customer is logged in and your app has permissions to read customer data "sub": "gid://shopify/Customer/" } ``` * #### Identify the customer from a session token ##### Description Send the session token to your app backend to identify the signed-in customer. Your backend decodes and verifies the token, then returns the customer ID. This requires \[access to protected customer data]\(/docs/apps/store/data-protection/protected-customer-data). ##### React ```tsx import {useEffect, useState} from 'react'; import { reactExtension, useApi, Text, } from '@shopify/ui-extensions-react/customer-account'; export default reactExtension( 'customer-account.order-status.block.render', () => , ); function Extension() { const {sessionToken} = useApi(); const [customerId, setCustomerId] = useState(null); useEffect(() => { async function identify() { const token = await sessionToken.get(); const response = await fetch( 'https://my-app.com/api/customer', { headers: { Authorization: `Bearer ${token}`, }, }, ); const {customerId} = await response.json(); setCustomerId(customerId); } identify(); }, [sessionToken]); return ( {customerId ? `Customer: ${customerId}` : 'Loading...'} ); } ``` ##### TS ```js import { extension, Text, } from '@shopify/ui-extensions/customer-account'; export default extension( 'customer-account.order-status.block.render', async (root, {sessionToken}) => { const loading = root.createComponent( Text, {}, 'Loading...', ); root.appendChild(loading); const token = await sessionToken.get(); const response = await fetch( 'https://my-app.com/api/customer', { headers: { Authorization: `Bearer ${token}`, }, }, ); const {customerId} = await response.json(); loading.replaceChildren( `Customer: ${customerId}`, ); }, ); ``` *** ## Best practices * **Request tokens close to usage**: Call `shopify.sessionToken.get()` immediately before making a request rather than storing the token for later, since tokens expire after 5 minutes. * **Verify tokens server-side**: Always validate the token signature, expiration (`exp`), and audience (`aud`) on your backend using your app's shared secret. * **Handle token errors gracefully**: Wrap token retrieval and fetch calls in try-catch blocks so your extension can display a meaningful message if authentication fails. *** ## Limitations * Session tokens expire after 5 minutes. Your backend must handle expired tokens and your extension should request a new token for each request. * The `sub` claim is only present when the customer is signed in and your app has the `read_customers` scope. Don't rely on it being available in all contexts. * Session tokens are signed JWTs intended for your backend only. Don't expose sensitive claims to the customer or use them for client-side authorization decisions. ***