Expiring offline access tokens required
UpcomingExpiring offline tokens required for all public apps · 82 days
From 2027-01-01 Shopify rejects non-expiring offline access tokens on Admin API requests from public apps, so every public app must migrate to expiring tokens.
Timeline
- Not reachedExpiring offline tokens required for all public apps
Who's affected
- App developers
Public apps must use expiring offline access tokens. This has been required for newly created public apps since 2026-04-01. On 2027-01-01 it becomes required for every public app, including ones created before that date.
Custom apps, including merchant-created apps from the Dev Dashboard or the admin, are not affected. Per the migration guide, enforcement applies to GraphQL Admin API requests.
What breaks
After 2027-01-01, Shopify rejects Admin API requests that use a non-expiring offline token. The response is a 403 Forbidden with the message "Non-expiring access tokens are no longer accepted for the Admin API". Until the app re-authenticates with an expiring token, that merchant's data stops syncing and any feature that calls the Admin API fails.
A missing access scope also returns a 403, so match on the message text before concluding it is this change.
How to check
- Is the app public? If it is a custom app, nothing changes.
- Do you store and use offline tokens that came back without
expires_in? A token response that includesexpires_inis an expiring token. - Check your auth code path. Apps that never opted in still receive non-expiring tokens.
The migration guide does not describe a status endpoint that tells you which stored tokens are which, so audit your own token storage.
Check whether your store is affected with the store checker.
How to fix
Apps on Shopify's template (@shopify/shopify-app-remix or the React Router template). Turn on the expiringOfflineAccessTokens future flag in shopifyApp(), then run shopify app deploy.
Token exchange. Add expiring=1 to the ID token exchange request.
Authorization code grant. Add expiring=1 to the request.
Tokens you already store. Exchange each stored token for an expiring one. Send a token exchange request with your client credentials, pass the stored token as subject_token, and set requested_token_type and expiring=1. Note:
- The migration permanently invalidates the old token.
- If the response is lost, you can retry within 7 days of the first exchange.
- Merchants do not need to reinstall the app.
Store and refresh. Save access_token, refresh_token, expires_in and refresh_token_expires_in. Refresh before the access token expires, and store the new refresh token every time, because each refresh returns a new one. Shopify's changelog describes the access token window as 60 minutes.
Need this migration handled?
I audit your store or app, build the replacement and ship it before the cutoff.