Executive summary
- What: Shopify now keeps a previously used refresh token valid until the app starts using its replacement, creating a recovery path when a refresh response never lands.
- Why: A lost or unsaved token pair used to become unrecoverable after a 60 minute window, stalling background work until a merchant reopened the app.
- Who: Any app or middleware holding expiring offline access tokens, including the custom ERP, OMS, and feed connectors your team maintains.
What changed
Expiring offline access tokens ship with a refresh token an app exchanges for a new pair before the access token dies. Every refresh returns a new access token and a new refresh token, and the app must store both. Previously, the refresh token an app had just presented stayed usable for roughly 60 minutes. If that response was lost in transit, or the process died before the write committed, the app was left holding a token that expired out from under it.
Now the presented refresh token stays usable until the app actually uses its replacement. Two limits still apply: recovery ends 30 days after the original refresh token's first use, and nothing extends a token past its normal 90 day lifetime. The moment the app presents the replacement, the preceding token is retired. There is no API version bump, no configuration change, and no opt-in, and apps on non-expiring offline tokens see no difference.
Why it matters
Token plumbing is invisible until it fails, and it fails quietly. Shopify issues the new pair, then the app's write does not commit: a worker is recycled mid-deploy, a database connection drops, a network hiccup swallows the response. The app still holds the old refresh token and, under the old rules, had one hour to notice. Past that, the integration was locked out with no server-side way back in.
The damage is downstream. Order exports to the ERP stop, inventory sync drifts, webhook-triggered jobs pile up, and nobody sees an error because no human is in the loop. Recovery meant a merchant opening the app in admin to re-run authorization, once per store on a multi-store org. For teams running custom apps against Shopify, this change turns a hard lockout into an ordinary retry.
Role-specific impact
- Marketers: Little direct impact, though fewer silent integration outages means fewer gaps in the order and customer data your ESP and analytics tools rely on.
- Developers: No migration work. Keep serializing refresh operations per shop, persist each token pair in one atomic write, and always refresh with the newest token. Treat the old token as a recovery path after a lost response, not a fallback to keep reusing.
- Store admins: Expect fewer reconnect-the-app tickets from integration partners. Still confirm an app resumed syncing rather than assuming silence means health.
Use-case example
Real-world scenario
A Plus merchant runs four regional stores in one org, with a custom NetSuite connector syncing orders and inventory every 15 minutes. A routine deploy recycles a worker seconds after Shopify returns a refreshed token pair for the Canadian store, and the write never commits. Under the old behavior the one hour window elapsed overnight and roughly 140 orders sat unexported until someone reopened the app the next morning: about nine hours of fulfillment delay for one region, plus a manual reconciliation pass. Under the new behavior the connector presents its stored refresh token on the next scheduled run and recovers on its own.
Implementation checklist
- Inventory your custom apps and middleware, and confirm which use expiring offline access tokens rather than non-expiring ones.
- Verify the access token and refresh token are persisted together in one atomic transaction, never as two separate writes.
- Serialize refresh operations per shop so two workers cannot refresh the same store concurrently.
- Check that retry logic re-presents the stored refresh token before escalating to full reauthorization.
- Never run token acquisition and refresh at the same time for one store, since each retires the other's result.
- Add alerting on consecutive refresh failures per shop so a stuck integration surfaces in hours, not days.
- Rehearse the failure in a development store: kill the process right after the refresh response and confirm the next run recovers.
FAQ
Q: Does this give our refresh tokens a longer life?
A: No. Recovery is capped at 30 days from the original refresh token's first use and never extends a token past its normal 90 day lifetime. It widens the recovery window, nothing more.
Q: Do we need to move to a new API version or change configuration?
A: No. The behavior applies automatically to apps already using expiring offline access tokens. If your app is built on a Shopify app template, refresh is already handled for you.
Resources
Shopify's reference on offline access tokens covers token lifetimes, refresh rotation, and retirement rules in detail.
Need guidance? Talk to Makro.