Shopify App Developers: Deprecated Offline Token Warning is Back! Here's How to Fix It (Community Insights)
Hey fellow Shopify app developers and store owners! It seems like many of us have been scratching our heads recently over a familiar, unwelcome guest making a comeback: that pesky "deprecated offline access token" warning in our Shopify Partner dashboards. Remember when we thought we'd squashed that bug back in September? Well, as one community member, Iciren, recently shared, after the new Shopify dashboard UI/UX rolled out, the warning is back with a vengeance!
It’s a bit like déjà vu, isn't it? You put in the work, follow the docs, and then poof, it's back. This isn't just a cosmetic annoyance; it points to a critical underlying issue that needs our attention before the January 1, 2027 deadline. Let's dive into what the community's been saying and what we can do to fix this for good.
What's Happening and Why the Warning Returned?
First off, let's quickly recap. Shopify is moving away from long-lived, non-expiring offline access tokens to a more secure system of expiring offline access tokens. This is a good thing for security, but it means our apps need to adapt. The deadline for this transition is January 1, 2027.
The core of the problem, as Shawn-Z eloquently put it in the thread, is that if you skip a bulk migration, any store that hasn’t opened your app since you implemented your initial fix is still holding onto the old, non-expiring token. And here's the kicker: the warning counts API calls from the last 14 days. So, if even one leftover old token is used for an API call, that warning comes right back to haunt your dashboard!
Another crucial point, highlighted by Frec3, is that new app installations might be inadvertently acquiring old-style tokens. If your OAuth code grant or the token exchange on the app's first load doesn't explicitly send expiring=1, then every new or reinstalled store gets a non-expiring token, and guess what? The warning reappears a couple of weeks later.
The Real Impact: Why You Can't Ignore This
You might be thinking, "Okay, but if my app only uses the API when the merchant is actively in the app, isn't it mostly harmless?" Shawn-Z clarifies that while the next app load will trigger a token exchange, giving them an expiring pair, the real danger lies with background operations. Think about it: webhooks keep arriving for those shops, and any API call you make while handling one, or from a scheduled job, will fail quietly if the token is old. It'll keep failing until the merchant happens to open your app again. That's a huge risk for data integrity and app functionality!
Community-Driven Solutions: How to Tackle This Head-On
Good news! Our community has been pooling their knowledge, and there are clear paths forward. Here are the top strategies:
1. Proactive Token Migration: The Recommended Path
This is the most robust solution, advocated by v.marychenka and Shawn-Z. You need to proactively exchange those old tokens for expiring ones for all your existing stores. This ensures every store is on the new system, regardless of when they last opened your app.
Step-by-Step Instructions for Token Exchange:
-
Identify Stores with Old Tokens: You'll need a list of stores that haven't yet updated their tokens. This might involve checking your database for tokens without an expiry date or refresh token.
-
Perform a POST Request per Store: For each identified store, you'll need to send a POST request to their specific `access_token` endpoint. Here’s the structure v.marychenka shared:
POST https://{shop}.myshopify.com/admin/oauth/access_token Content-Type: application/json { "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange", "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "subject_token": "OLD_NON_EXPIRING_ACCESS_TOKEN", "subject_token_type": "urn:shopify:params:oauth:token-type:offline-access-token", "requested_token_type": "urn:shopify:params:oauth:token-type:offline-access-token", "expiring": 1 }Important Note: Replace
{shop},YOUR_CLIENT_ID,YOUR_CLIENT_SECRET, andOLD_NON_EXPIRING_ACCESS_TOKENwith your specific values. Theexpiring: 1parameter is key here! -
Test on a Dev Store FIRST: This is critical! As v.marychenka warns, "migration permanently invalidates the old token for GraphQL Admin API requests." Make sure your handling of the new expiring token pair (access token + refresh token) is solid before rolling this out to production.
-
Save the New Token Pair: Once you get the new expiring access token and refresh token, immediately save them to replace the old token in your database.
2. Securing New App Installations
This is crucial for preventing the warning from returning due to new installs. Frec3's advice here is gold:
-
Verify
expiring=1in OAuth: Double-check that any path in your app that gets a token for a new install (during the OAuth code grant or first load token exchange) sendsexpiring=1. If it doesn't, new stores will keep getting non-expiring tokens. -
Check Shopify App Libraries: If you're using official Shopify app libraries like
@shopify/shopify-app-remixor@shopify/shopify-app-react-router, ensure theexpiringOfflineAccessTokensflag is correctly set totruein your productionshopifyApp()configuration. -
Inspect Recent Tokens: A good diagnostic step is to look at the stored tokens for stores installed in the last month. If any of them lack a refresh token or an expiry date, your process is likely still requesting old-style tokens for new installs.
3. The "Nuclear" Option: Client Secret Rotation
Bhavin_iflair shared a more drastic, but effective, approach. If you're struggling to identify which shops are calling the deprecated API or just want a clean slate, rotating your client secret can force a system-wide update:
-
Rotate Your Client Secret: Generate a new client secret in your Partner Dashboard.
-
Convert Existing Tokens: Develop a process to update all existing shops' access tokens to use this new client secret. This might involve a re-authentication flow or a bulk update if your app architecture supports it.
-
Delete the Old Secret: Once all stores are on the new secret, delete the old one. This effectively invalidates any remaining old tokens associated with the old secret.

This is a significant undertaking, but it can be a comprehensive solution if other methods prove too difficult to pinpoint specific problematic tokens.
A Quick Note on Managing Expiring Tokens Long-Term
Iciren raised a good question about managing these new expiring tokens, especially for inactive stores. Shawn-Z clarified that refresh tokens last 90 days from issuance, and every refresh gives you a new pair with a fresh 90 days. For shops you don't do background work for, you don't need a "keep-alive" job; they'll simply exchange for a new token pair on their next app open.
However, for shops where your app does perform background tasks (like webhooks or scheduled jobs), a small job that refreshes any token getting close to its 90-day expiry is absolutely worth it. Otherwise, a webhook arriving on day 100 will find no valid token to make its calls, leading to silent failures.
So, there you have it. The return of the deprecated token warning isn't just a glitch; it's a reminder to ensure our apps are fully compliant with Shopify's evolving security standards. By taking these steps, especially the proactive token migration and securing new installations, we can banish that warning from our dashboards and ensure our apps continue to run smoothly and securely for all our merchants.