---
title: Set up session tokens with App Bridge 2.0
description: >-
  Set up session token authentication for embedded apps using App Bridge 2.0,
  for apps built before the current app templates were available.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/authentication-authorization/legacy/app-bridge-2-setup
  md: >-
    https://shopify.dev/docs/apps/build/authentication-authorization/legacy/app-bridge-2-setup.md
---

# Set up session tokens with App Bridge 2.​0

**Caution:**

This page covers App Bridge 2.0. App Bridge 2.0 calls the short-lived JWT a session token; the current App Bridge calls the same concept an ID token. See [About app authentication](https://shopify.dev/docs/apps/build/authentication-authorization) for the modern approach. If you're building a new app, the [React Router template](https://shopify.dev/docs/api/libraries-and-templates#app-templates) handles all of this for you. This content is maintained for teams maintaining existing App Bridge 2.0 apps.

App Bridge 2.0 is the npm-based predecessor to the current script-tag App Bridge. Unlike the current version, it doesn't handle session tokens automatically. In App Bridge 2.0, embedded apps retrieve session tokens manually using the `getSessionToken` helper and attach them to backend requests using `authenticatedFetch`. The backend then decodes and verifies the token before exchanging it for an API access token via token exchange.

We recommend using the [Shopify App gem](https://github.com/Shopify/shopify_app) or [Shopify Node API library](https://github.com/Shopify/shopify-app-js/tree/main/packages/apps/shopify-api) to decode and verify tokens rather than implementing verification manually.

***

## Get a session token

The `getSessionToken` helper retrieves a session token from Shopify. It dispatches the `APP::SESSION_TOKEN_REQUEST` action and resolves when App Bridge responds with `APP::SESSION_TOKEN_RESPOND`.

```js
import createApp from "@shopify/app-bridge";
import { getSessionToken } from "@shopify/app-bridge/utilities";


const app = createApp({
  apiKey: "12345",
  host: new URLSearchParams(location.search).get("host"),
});


const sessionToken = await getSessionToken(app);
```

`getSessionToken` returns a `Promise` that resolves with the session token or rejects with `APP::ERROR::FAILED_AUTHENTICATION` if the token is `undefined`.

***

## Authenticate requests

The `authenticatedFetch` helper attaches the session token as a `Bearer` authorization header on requests to your backend.

```js
import { authenticatedFetch } from "@shopify/app-bridge/utilities";


const authFetch = authenticatedFetch(app);
const response = await authFetch("/api/products");
```

To add custom headers or caching logic, pass a custom fetch wrapper as the second argument. The wrapper receives the request URI and merged options including the `Authorization` header. Make sure your wrapper passes all options through:

```js
import deepMerge from "@shopify/app-bridge/actions/merge";


const yourCustomFetchWrapper = (uri, options) => {
  const aggregateOptions = deepMerge(options, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
  });
  return fetch(uri, aggregateOptions);
};


const shopifyFetch = authenticatedFetch(app, yourCustomFetchWrapper);
```

***

## Decode and verify session tokens on the server

A session token is a JWT with the structure `<header>.<payload>.<signature>`, all base64url-encoded. Session tokens are signed with HS256 using your app's client secret.

### Verify the payload claims

Extract and verify the following fields from the payload:

| Field | Verification |
| - | - |
| `exp` | Must be in the future |
| `nbf` | Must be in the past |
| `iss`, `dest` | Hostnames must match. `dest` is the shop origin (`myshop.myshopify.com`). |
| `aud` | Must match your app's client ID |
| `sub` | User ID of the authenticated user |

Discard the token and return an error if any check fails.

**Note:**

Without third-party cookies, CSRF tokens in cookies aren't always possible. The session token serves as an alternative. You can trust it was issued by Shopify to your app's frontend.

### Verify the signature

1. Take the `<header>.<payload>` portion of the token.
2. Hash it with SHA-256 and sign using HS256 with your app's client secret as the signing key.
3. Base64url-encode the result.
4. Compare it to the `<signature>` portion of the token.

Use [JWT.io](https://jwt.io/) as a reference for decoding tokens during development.

***

## After verification

Once you've verified the session token, exchange it for an API access token using [token exchange](https://shopify.dev/docs/apps/build/authentication-authorization/implement-token-exchange). Store the access token and use it on subsequent GraphQL Admin API requests with the `X-Shopify-Access-Token` header.

If your app doesn't have a valid offline or online access token, redirect to a bounce page that loads the App Bridge script before redirecting back to the requested path. This ensures the session token is available in the `Authorization` header on the follow-up request.

Don't embed protected data in the unauthenticated HTML you return before verification. Expose only the shop domain there, and serve protected data from an authenticated API route once the token is verified.

For online access token expiry, request a new token via token exchange when the existing token expires.

***
