September 26, 2026 · Ahmed · More by Ahmed
Shopify's ID Tokens: What Your Backend Must Validate
Shopify renamed session tokens to ID tokens. Here's what a custom backend must validate — and how to handle expiry correctly.
From Session Token to ID Token
Shopify's developer docs now call the JWT that authenticates embedded app requests an "ID token" — the same credential previously called a "session token." The rename comes with a sharper explanation of what the token actually does: it authenticates the user, not the app. Per the docs, an ID token "carries no permissions, and you can't use it to call a Shopify API." It has to be exchanged for an access token first, and the docs are explicit that the ID token is never sent to the API.
That distinction matters for anyone building a custom backend instead of relying on Shopify's own app template, because the two tokens are validated completely differently and serve different jobs. An access token proves your app is authorized and carries the scopes that make it work. An ID token vouches for the specific user hitting your endpoint from a specific store — nothing more.
What a Custom Backend Must Validate
App templates that ship with Shopify CLI validate ID tokens automatically. If you've built your own auth layer, the docs specify what to check yourself: verify the signature with HS256 against your app's client secret, then check four claims — exp must be in the future, nbf must be in the past, aud must match your app's client ID, and the hostnames in iss and dest must match. Failing any of these means rejecting the request with a 401 before you ever call Shopify's token endpoint.
The token also carries informational claims — sub, sid, jti, and iat — that identify the user and session but aren't part of the validation check. They're there to read, not to gate access on.
Handling Expiry Without Guessing
ID tokens live for one minute after issuance. That's short by design, and it means an embedded app should fetch a fresh token per request rather than cache one — a token pulled from App Bridge's cache may already have less than the full minute left on it.
When validation fails because a token has expired, the documented pattern isn't a generic error. It's a 401 response carrying the X-Shopify-Retry-Invalid-Session-Request header, which tells App Bridge to fetch a new ID token and retry the request once. Shopify frames this explicitly as routine, not a fault: since the token's whole lifetime is about a minute, hitting expiry is expected traffic, and the retry contract exists precisely so a backend doesn't need to treat it as an outage.
For a systems team maintaining a custom auth path, that's the practical takeaway: build the 401-plus-retry-header response into your token-validation error path from day one, rather than bolting it on after a support ticket about "random" login failures.