Getting started with session token authentication
This tutorial explains how to set up session token authentication for your embedded app.
Many of the topics discussed in this tutorial are covered in the following video:
After you've finished this tutorial, you'll know how to set up session token authentication for your app.
RequirementsAnchor link to section titled "Requirements"
- You've created an app from your Partner Dashboard or Shopify CLI.
- The app is embedded in the Shopify admin.
- You've learned about how session tokens work.
- The app uses App Bridge version 2.0.
- You've created an App Bridge instance.
RecommendationsAnchor link to section titled "Recommendations"
We recommend using the Shopify App gem, Shopify Node API library, or Shopify PHP API library to decode and verify the authenticity of the session token.
Step 1: Get a session tokenAnchor link to section titled "Step 1: Get a session token"
getSessionToken helper retrieves a session token from Shopify. It sets up a subscription on the Shopify App Bridge client to listen for the
APP::SESSION_TOKEN_RESPOND action and then immediately dispatches the
In your app, set up the Shopify App Bridge client and import
getSessionToken using the following code:
Where your app requires a session token, specify the following code:
getSessionToken returns a
Promise, which either resolves with the session token, or rejects with an
APP::ERROR::FAILED_AUTHENTICATION error when the session token is
Step 2: Authenticate your requestsAnchor link to section titled "Step 2: Authenticate your requests"
authenticatedFetch helper function authenticates your requests using the session token. The function gets the session token from Shopify App Bridge and passes in the
Authorization header to your subsequent
app: The App Bridge instance.
fetchOperation: Optional. Define a custom fetch wrapper.
The following example shows how to use
authenticatedFetch with a custom ApolloLink:
Use a custom fetch wrapperAnchor link to section titled "Use a custom fetch wrapper"
If you want to add custom headers, caching, or special treatment of requests, then you can optionally pass in a custom fetch wrapper function to the
app-bridge function (
authenticatedFetch) returns your custom fetch wrapper function along with an authenticated
Authorization header appended to the request options provided.
Any custom fetch function that you provide needs to append all the appropriate options, including headers. The following example shows how to append options:
Step 3: Decode session tokens for incoming requestsAnchor link to section titled "Step 3: Decode session tokens for incoming requests"
You need to add middleware that detects requests with a session token present, verifies that the session token's signature is correct, and then builds a session based on the shop and user information included in the token.
The Shopify App gem, Shopify Node API library, and Shopify PHP API library provide middleware and utilities for decoding session tokens.
If your app isn't built using the libraries mentioned above, then you can obtain session details and verify the session token's signature manually.
Optional: Obtain session details and verify the session token manuallyAnchor link to section titled "Optional: Obtain session details and verify the session token manually"
If your app isn't built using the Shopify App gem, the Shopify Node API library, the Shopify PHP API library, or another library with session tokens included, then use the following steps to help you manually decode the session token and verify that it's valid.
Obtain and verify session detailsAnchor link to section titled "Obtain and verify session details"
A session token is a JWT string with the following structure:
<header>.<payload>.<signature>. You can obtain the session details from the payload and then verify the contents as follows:
expvalue from the payload.
Verify that the datetime value is in the future.
nbfvalue from the payload.
Verify that the datetime value was in the past.
destfields from the payload.
The top-level domains should match. The
destfield specifies the shops that the request originated from. For example,
audvalue from the payload.
Verify that the value matches the client ID of your app.
subvalue from the payload.
This is the ID of the user that made the request.
If any of the above steps fail, then discard the payload, stop processing the request, and respond with an error.
Verify the session token's signatureAnchor link to section titled "Verify the session token's signature"
To verify that the signature is correct, you need to generate a new Base64url-encoded signature using the app’s shared secret.
Session tokens are signed using the HS256 algorithm. This is a symmetric algorithm. The signing key is the shared secret for your Shopify app. A session token is a JWT string with the following structure:
All three sections are base64 encoded.
Use the following steps to verify that the issued token has a valid signature. Refer to JWT.io for a useful JWT decoder tool.
- Take the
<header>.<payload>portion of the string and hash it with SHA-256.
- Sign the string using the HS256 algorithm by using the app’s secret as the signing key.
- Base64url-encode the result.
- Verify that the result is the same as the signature that was sent with the session token.
Step 4: Allow authenticated requestsAnchor link to section titled "Step 4: Allow authenticated requests"
To allow authenticated requests, you need to update the route that serves the app so that it allows unauthenticated requests. You also need to add logic to the unauthenticated route to detect if this is the first time that the shop is loading your app.
Update the routeAnchor link to section titled "Update the route"
If the page that's rendered by the route depends on an authenticated request to the route, then remove the protected data from the response and expose the data to the frontend using an authenticated API route.
For example, your app might be embedding protected merchant information in its initial HTML response. The only merchant information that should be available on unauthenticated routes is the shop domain, which is passed in as a query parameter in the app URL.
Add logic to the unauthenticated routeAnchor link to section titled "Add logic to the unauthenticated route"
If your app doesn't have a offline access token for the shop, then the route should respond with a redirect to send the user to the OAuth login flow. This ensures that the app is installed and receives its shop token.
If your app uses online access tokens, then you need to redirect the user to the OAuth login flow a second time.
Step 5: Mark shop records as uninstalled using the Anchor link to section titled "Step 5: Mark shop records as uninstalled using the app/uninstalled webhook"
To ensure OAuth continues to work with session tokens, your app must update its shop records when a shop uninstalls your app. An app can receive notifications of uninstall events by subscribing to the
The following sections show a Ruby implementation that subscribes to the webhook and updates the records.
Set up the webhookAnchor link to section titled "Set up the webhook"
add_webhook generator from the shopify_app gem to set up the
app/uninstalled webhook for the app. The following code adds the
app/uninstalled webhook to your app config and creates the
AppUninstalledJob job class so that you can add uninstallation handler logic.
Mark the shop record as uninstalledAnchor link to section titled "Mark the shop record as uninstalled"
To mark the record as uninstalled, you need to update the
AppUninstalledJob job class. In the following example, the app marks the shop as uninstalled by deleting the Shop record:
Define a background jobAnchor link to section titled "Define a background job"
You need to define a background job to ensure that shops with existing installations also have the uninstall webhook set up. In the following example, the
RegisterWebhooksForActiveShop job is defined to iterate all shop records in the database and configure the webhooks.
Enqueue the background jobAnchor link to section titled "Enqueue the background job"
RegisterWebhooksForActiveShops background job to apply the webhook registration. For details on enqueuing ActiveJobs on Rails, refer to the Rails guides.
Step 6: Handle changes to access scopes requested by your appAnchor link to section titled "Step 6: Handle changes to access scopes requested by your app"
Your app needs to keep track of the access scopes authorized for each shop to determine whether they match the scopes requested by your app.
If the authorized scopes don't match the scopes currently requested by your app, then your app needs to initiate the OAuth login flow to ask the merchant to authorize the new scopes:
To determine whether currently authorized scopes match currently requested scopes, you can store the current access scopes on your app or query them using the GraphQL Admin API or REST Admin API:
GraphQL Admin API: Query the
accessScopesfield on the
REST Admin API: Make a request to the
GET /admin/oauth/access_scopes.jsonendpoint on the
It's important to consider app load performance when making network calls to request access scopes using APIs.
Step 7: Handle the expiry of online access tokensAnchor link to section titled "Step 7: Handle the expiry of online access tokens"
Apps that use online access tokens need to keep track of whether the online access token is expired.
If the online access token is expired, then your app needs to direct the user to go through the OAuth login flow to retrieve a new online access token.
Step 8: Verify that the session token is being sentAnchor link to section titled "Step 8: Verify that the session token is being sent"
Your app should now work using session token authentication. When any network calls are made, you should see the session token being sent in the header:
- Authorize your app that was created in the Partner Dashboard or Shopify CLI using OAuth.