Authenticate an embedded app using session tokens
This tutorial describes the frontend and backend changes required to set up session token authentication in your embedded app.
- You've created a public app or custom app from your Partner Dashboard.
- The app is embedded in Shopify admin.
- The app uses Shopify App Bridge version 1.23 or higher.
Make frontend changes
You need to make the following changes to the frontend to set up session token authentication in your embedded app.
Load Shopify App Bridge in a skeleton page
For more details on setting up Shopify App Bridge, refer to Getting started with Shopify App Bridge.
Start fetching protected data with session tokens
After you create the App Bridge instance, you can start getting session tokens and passing them in requests to fetch protected merchant data.
Each time you make a request to fetch protected resources from the app backend, you need to include the session token as an
Authorization header in the following format:
Authorization: Bearer <session_token>.
App Bridge provides utilities for getting session tokens and passing them into requests made to the app backend. For more information, refer to Get session tokens using App Bridge utilities.
Make backend changes
You need to make the following changes to the backend to set up session token authentication in your embedded app.
Decode session tokens for incoming requests
If your app isn't built using the libraries mentioned above, then you can obtain session details from a session token manually.
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 the shop is loading your app.
1. Update the route
If the page that is server-rendered by this route depends on an authenticated request to the route, remove the protected data from the response and expose it to the frontend using an authenticated API route.
For example, your app might be embedding merchant information in its initial HTML response.
The only merchant information available on unauthenticated routes is the shop domain passed in as a query parameter in the app URL.
2. Add logic to the unauthenticated route
If your app doesn't have a shop/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 user/online access tokens, then you will need to redirect the user a second time to the OAuth flow.
You need to add middleware that detects requests with a session token present and builds a session based on the shop and user information included in the token.
To verify the authenticity of a session token, refer to Verify the signature.
Mark shop records as uninstalled using the
To ensure OAuth continues to work with session tokens, your app needs to make sure shop records are updated when a shop uninstalls your app. Your app can receive notifications of uninstalls by subscribing to the
You should also set up the webhook subscription for any shops that have already installed your app. For example, you could use the webhookSubscriptionCreate endpoint, or define a background job to subscribe to the webhook.
Handle changes to access scopes requested by your app
Your app needs to keep track of the access scopes currently authorized for each shop to determine whether they match the scopes currently requested by your app.
If the scopes currently authorized 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.
Handle the expiry of online access tokens
Apps that use online access tokens need to keep track of whether the token is expired.
If the online access token is expired, then the user needs to go through the OAuth login flow to retrieve a new token.
Obtain session details manually
If your app isn't built using the Shopify App gem, the Shopify Node API, 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. The session token is signed using the shared secret of your Shopify app.
- Decode the session token, verify the signature, and obtain the headers and payload.
expvalue from the payload.
Verify that it's in the future.
nbfvalue from the payload.
Verify that it 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 it matches the API key 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 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. There is a useful token analysis tool at JWT.io.
- 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.
Make sure shop records are updated
To ensure OAuth continues to work with session tokens, your app must update its shop records in the event a shop uninstalls your app. The app can receive notifications of these events by subscribing to the
The following sections show a Ruby implementation that subscribes to the webhook and updates the records.
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 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 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 job
RegisterWebhooksForActiveShops background job to apply the webhook registration. For details on enqueuing ActiveJobs on Rails, refer to the Rails guides.
Verify 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:
- Convert a multi-page, server-side rendered (SSR) app to use App Bridge authentication with Turbolinks.