This tutorial explains how to set up session token authentication for your embedded app. > Note: > The below guide only applies to App Bridge 2.0. The [current version of App Bridge](/docs/api/app-bridge) automatically adds session tokens to requests coming from your app. > > If you want to set up session token authentication for a multi-page server-side rendered (SSR) app, then you need to instead set your app to use Turbolinks. For an example, refer to the [Turbolinks and JWT sample app](https://github.com/Shopify/turbolinks-jwt-sample-app). Many of the topics discussed in this tutorial are covered in the following video: <div class="video-embed-wrapper"> <figure> <iframe src="https://www.youtube.com/embed/Vq0aWTaJDAY?cc_lang_pref=&cc_load_policy=1" width="800" height="450" allowfullscreen></iframe> </figure> </div> ## Outcomes After you've finished this tutorial, you'll know how to set up session token authentication for your app. ## Requirements - You've [created an app](/docs/apps/build/scaffold-app) from your Partner Dashboard or Shopify CLI. - The app is [embedded in the Shopify admin](/docs/api/app-bridge/previous-versions/app-bridge-from-npm/app-setup#turn-on-embedding-in-the-partner-dashboard). - You've learned about [how session tokens work](/docs/apps/build/authentication-authorization/session-tokens). - The app uses [App Bridge version 2.0](docs/api/app-bridge/previous-versions/app-bridge-from-npm/app-setup). - You've [created an App Bridge instance](/docs/api/app-bridge-library). > Tip: > You can use [Shopify CLI](/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](/docs/apps/build/authentication-authorization/session-tokens) and [token exchange](/docs/apps/build/authentication-authorization/access-tokens/token-exchange). ## Recommendations We recommend using the [Shopify App gem](https://github.com/Shopify/shopify_app), [Shopify Node API library](https://github.com/Shopify/shopify-app-js/tree/main/packages/apps/shopify-api), or [Shopify PHP API library](https://github.com/Shopify/shopify-api-php) to decode and verify the authenticity of the session token. ## Step 1: Get a session token The `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 `APP::SESSION_TOKEN_REQUEST` action. In your app, set up the Shopify App Bridge client and import `getSessionToken` using the following code: <p> <div class="react-code-block" data-preset="basic"> <div class="react-code-block-preload ThemeMode-dim"> <div class="react-code-block-preload-bar basic-codeblock"></div> <div class="react-code-block-preload-placeholder-container"> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> </div> </div> <script type="text/plain" data-language="js"> import createApp from "@shopify/app-bridge"; import { getSessionToken } from "@shopify/app-bridge/utilities"; const app = createApp({ apiKey: "12345", // API key from the Partner Dashboard host: "YWRtaW4uc2hvcGlmeS5jb20vc3RvcmUvemwtMDMwNDExMjE", // host from URL search parameter }); </script> </div> </p> Where your app requires a session token, specify the following code: <p> <div class="react-code-block" data-preset="basic"> <div class="react-code-block-preload ThemeMode-dim"> <div class="react-code-block-preload-bar basic-codeblock"></div> <div class="react-code-block-preload-placeholder-container"> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> </div> </div> <script type="text/plain" data-language="js"> const sessionToken = await getSessionToken(app); </script> </div> </p> `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 `undefined`. ## Step 2: Authenticate your requests The `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 `fetch` requests. ### Parameters - `app`: The App Bridge instance. - `fetchOperation`: Optional. Define a custom fetch wrapper. The following example shows how to use `authenticatedFetch` with a custom ApolloLink: <p> <div class="react-code-block" data-preset="basic"> <div class="react-code-block-preload ThemeMode-dim"> <div class="react-code-block-preload-bar basic-codeblock"></div> <div class="react-code-block-preload-placeholder-container"> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> </div> </div> <script type="text/plain" data-language="js"> import ApolloClient from "apollo-client"; import { authenticatedFetch } from "@shopify/app-bridge/utilities"; import createApp from "@shopify/app-bridge"; import { HttpLink } from "apollo-link-http"; import { InMemoryCache } from "apollo-cache-inmemory"; const app = createApp({ apiKey: "12345", // API key from the Partner Dashboard host: "YWRtaW4uc2hvcGlmeS5jb20vc3RvcmUvemwtMDMwNDExMjE", // host from URL search parameter }); const client = new ApolloClient({ link: new HttpLink({ credentials: "same-origin", fetch: authenticatedFetch(app), // ensures that all requests triggered by the ApolloClient are authenticated }), cache: new InMemoryCache(), }); </script> </div> </p> ### 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 `fetchOperation` parameter. 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: <p> <div class="react-code-block" data-preset="basic"> <div class="react-code-block-preload ThemeMode-dim"> <div class="react-code-block-preload-bar basic-codeblock"></div> <div class="react-code-block-preload-placeholder-container"> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> </div> </div> <script type="text/plain" data-language="js"> import ApolloClient from "apollo-client"; import { authenticatedFetch } from "@shopify/app-bridge/utilities"; import createApp from "@shopify/app-bridge"; import deepMerge from "@shopify/app-bridge/actions/merge"; import { HttpLink } from "apollo-link-http"; import { InMemoryCache } from "apollo-cache-inmemory"; // Sample custom fetch wrapper const yourCustomFetchWrapper = (uri, options) => { const aggregateOptions = deepMerge(options, { method: "POST", headers: { "Content-Type": "application/json" }, }); return fetch(uri, aggregateOptions); }; const app = createApp({ apiKey: "12345", // API key from the Partner Dashboard host: "YWRtaW4uc2hvcGlmeS5jb20vc3RvcmUvemwtMDMwNDExMjE", // host from URL search parameter }); const client = new ApolloClient({ link: new HttpLink({ credentials: "same-origin", fetch: authenticatedFetch(app, yourCustomFetchWrapper), // ensures that your custom fetch wrapper is authenticated }), cache: new InMemoryCache(), }); </script> </div> </p> ## 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](https://github.com/Shopify/shopify_app), [Shopify Node API library](https://github.com/Shopify/shopify-app-js/tree/main/packages/apps/shopify-api), and [Shopify PHP API library](https://github.com/Shopify/shopify-api-php) 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 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 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: 1. Extract the `exp` value from the payload. Verify that the datetime value is in the future. 2. Extract the `nbf` value from the payload. Verify that the datetime value was in the past. 3. Extract the `iss` and `dest` fields from the payload. The top-level domains should match. The `dest` field specifies the shops that the request originated from. For example, `myshop.myshopify.com`. 4. Extract the `aud` value from the payload. Verify that the value matches the client ID of your app. 5. Extract the `sub` value 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. > Note: > Without third-party cookies, setting Cross-Site Request Forgery (CSRF) tokens in a cookie might not be possible. The session token serves as an alternative to CSRF tokens, because you can trust that the session token has been issued by Shopify to your app frontend. #### 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: `<header>.<payload>.<signature>` All three sections are base64 encoded. Use the following steps to verify that the issued token has a valid signature. Refer to [JWT.io](https://jwt.io/) for a useful JWT decoder tool. 1. Take the `<header>.<payload>` portion of the string and hash it with SHA-256. 2. Sign the string using the HS256 algorithm by using the app’s secret as the signing key. 3. Base64url-encode the result. 4. Verify that the result is the same as the signature that was sent with the session token. ## 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 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 app user information in its initial HTML response. The only app user 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 route If your app doesn't have a valid [online](/docs/apps/build/authentication-authorization/access-tokens/online-access-tokens) or [offline](/docs/apps/build/authentication-authorization/access-tokens/offline-access-tokens) access token, then it should get a new session token from App Bridge. The session token should be passed into the app backend to exchange for an online and offline access token using [token exchange](/docs/apps/build/authentication-authorization/access-tokens/token-exchange). ## 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 `app/uninstalled` [webhook](/docs/api/admin-rest/latest/resources/webhook). The following sections show a Ruby implementation that subscribes to the webhook and updates the records. ### Set up the webhook Use the [`add_webhook` generator from the shopify_app gem](https://github.com/Shopify/shopify_app/blob/main/docs/shopify_app/webhooks.md#manage-webhooks-using-shopifyappwebhooksmanager) 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. <p> <div class="react-code-block" data-preset="basic"> <div class="react-code-block-preload ThemeMode-dim"> <div class="react-code-block-preload-bar basic-codeblock"></div> <div class="react-code-block-preload-placeholder-container"> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> </div> </div> <script type="text/plain" data-language="none"> rails g shopify_app:add_webhook -t app/uninstalled -a {your_app_url}/webhooks/app_uninstalled </script> </div> </p> ### 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: <p> <div class="react-code-block" data-preset="basic"> <div class="react-code-block-preload ThemeMode-dim"> <div class="react-code-block-preload-bar basic-codeblock"></div> <div class="react-code-block-preload-placeholder-container"> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> </div> </div> <script type="text/plain" data-language="ruby"> class AppUninstalledJob < ActiveJob::Base def perform(args) shop = Shop.find_by(shopify_domain: args[:shop_domain]) mark_shop_as_uninstalled(shop) end private def mark_shop_as_uninstalled(shop) shop.uninstall! if shop end end </script> </div> </p> ### 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. <p> <div class="react-code-block" data-preset="basic"> <div class="react-code-block-preload ThemeMode-dim"> <div class="react-code-block-preload-bar basic-codeblock"></div> <div class="react-code-block-preload-placeholder-container"> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> <div class="react-code-block-preload-code-container"> <div class="react-code-block-preload-codeline-number"></div> <div class="react-code-block-preload-codeline"></div> </div> </div> </div> <script type="text/plain" data-language="ruby"> class RegisterWebhooksForActiveShops < ApplicationJob queue_as :default def perform register_webhooks_for_active_shops end private def register_webhooks_for_active_shops Shop.find_each do |shop| ShopifyApp::WebhooksManagerJob.perform_now( shop_domain: shop.shopify_domain, shop_token: shop.shopify_token, webhooks: ShopifyApp.configuration.webhooks ) end end end </script> </div> </p> ### Enqueue the background job Enqueue the `RegisterWebhooksForActiveShops` background job to apply the webhook registration. For details on enqueuing ActiveJobs on Rails, refer to the [Rails guides](https://edgeguides.rubyonrails.org/active_job_basics.html). ## Step 6: Handle the expiry of online access tokens Apps that use [online access tokens](/docs/apps/build/authentication-authorization/access-tokens/online-access-tokens) need to keep track of whether the online access token is expired. If the online access token is expired, your app can request a new one using [token exchange](/docs/apps/build/authentication-authorization/access-tokens/token-exchange). ## Step 7: 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: <figure class="figure"><img src="https://cdn.shopify.com/shopifycloud/shopify_dev/assets/partners/jwt-authentication-1ad4361bef4ad7ae599478a7c90917694da192aa153dd5a1a24769e9658b7972.png" class="lazyload" width="1266" height="294"></figure> ## Next steps - Exchange your session token for an access token with [token exchange](/docs/apps/build/authentication-authorization/access-tokens/token-exchange).