Nothing about how your app makes Admin API requests will change when using expiring tokens vs. non-expiring tokens. Only the request for offline access tokens and the response will change (i.e. the response will include the TTL for the access token and also the refresh token with its TTL).
The simplest way to test your app is to start requesting expiring offline access tokens now, storing them plus the refresh token and the corresponding TTLs. Then make API requests as usual. You will also need to implement the refresh process to acquire new offline access tokens once they expire.
Once you’ve validated that your app has properly implemented the new expiring access token acquisition and refresh process then you can begin to migrate your app’s existing non-expiring offline access tokens.
@TerenceShopify The app partners’ concern is not how the expiring tokens work. That part is fairly straightforward. Our concern is that if a token expires due to an error, the quality of service provided by our app is degraded. All app partners care about maintaining a reliable service.
Our concerns are:
The token TTL is only 1 hour. That is very short for backend apps running processes that can last hours. It introduces additional complexity and creates more opportunities for failures. If we had 24 hours - It would give us much more breathing space.
The API documentation states that if a token exchange fails, there is a small retry window. However, it does not specify how small that window is. Is it a second, a minute, or an hour?
What should app partners do with seasonal shops that remain frozen for months? No solution has been provided for that scenario.
The token exchange functionality itself is the least of our concerns. Our concern is how we continue providing a high-quality service to our clients while avoiding service interruptions due to token exchange failure.
The token TTL is only 1 hour. That is very short for backend apps running processes that can last hours. It introduces additional complexity and creates more opportunities for failures. If we had 24 hours - It would give us much more breathing space.
The Shopify team considered various TTLs for these tokens and considered industry practices, OAuth2 specs, and our security team’s recommendations before settling on 60 minutes as the most appropriate TTL for the access tokens.
What should app partners do with seasonal shops that remain frozen for months? No solution has been provided for that scenario.
Apps can refresh access tokens for shops that are in a frozen state. In this scenario your app should make sure to refresh its access tokens before the 90 day refresh token TTL expires.
Hi Terence, are you able to confirm if this must be migrated for ALL apps? or only those shown on the dev dashboard as requiring a fix by 1st Jan?
All public apps will need to make this change by January 1 2027. If you have a mix of public and custom apps you will see in your Dev Dashboard list of apps that some apps have an API health warning and others do not. Those that do not have the warning may be custom apps, public apps that haven’t made an API request recently, or public apps that are already using expiring tokens. Public apps that were created on or after April 1 2026 already must use expiring offline access tokens.
@TerenceShopify Thank you for the great update! The frozen-shop token refresh support is excellent news!
Could you please clarify one final detail that is preventing us from migrating to expiring tokens?
The API documentation mentions that if a token exchange fails, there is a small retry window. However, it does not specify how long that window is. Can you clarify the timeframe for a small retry window?
This is the last piece of information we need before moving to expiring tokens.
The reason this is important is that Shopify experienced an outage on June 3, and a large number of stores were affected. If token exchanges had occurred during that period, more than 1,100 of our merchants could have been impacted. It is currently unclear how failed token exchanges would be handled in such a scenario, and whether merchants would ultimately need to re-authenticate.
Many things can go wrong in distributed systems, and our goal is to provide the highest possible service quality to our customers. If tokens can be permanently lost during an outage - that would directly affect our ability to do so.
We have some apps created pre ‘public apps’ some 10 years ago which do not fall into the mentioned categories.
They are not public apps, not custom apps, do not use expiring tokens yet do not have the warning. Does this mean those apps does not need to transition to expiring tokens?
If not, will they need to at some point in future (also will custom apps need to transition at some point in time in future), if so what will be the timeframe as we need to plan this with merchants.
I really liked the idea which would solve the problem for app developers:
If we perform a token exchange and something goes wrong, we should be able to perform another token exchange using the same access token and refresh token for a period of time, or until the newly issued access token successfully makes its first API call.
This would make the system much more resilient. If something breaks during the exchange process, we could recover easily without disrupting service for merchants.
I have a suggestion that could be helpful for both app developers and Shopify.
It would be great if the Partner Dev Dashboard provided an option to generate a temporary “secret recovery key” with a short expiration period (e.g., 1–2 hours). This key could be used to recreate access and refresh tokens in cases where they are lost or token generation fails at any point in the process.
I also believe this approach could be implemented safely, since the recovery key would be time-limited and generated only by authorized app partners.
Whilst this is a good step forward, those of us with highly automated background processes won’t be able to benefit much from this.
Should a fault occur, thousands of merchants will still be impacted for several hours as we have to manually generate and refresh keys.
There needs to be a pathway for automated recovery in case the authentication service fails for whatever reason, after all, the ultimate goal here is to provide a service to the merchant.
You are absolutely right. We also have many automated background processes, and I don’t think this aspect has been fully considered by the Shopify team.
An offline recovery secret would actually be less of a security risk than a refresh token, since anyone who gains access to the token store would typically get both the access and refresh tokens. A recovery secret, on the other hand, could be securely stored in a secret manager and only used when recovery is needed.
Or perhaps an even better solution would be to support an offline token combined with a secret key for authentication.
@TerenceShopify The documentation should define the “short retry window” in precise units that leave no room for interpretation within engineering practice.
Recently, we have seen outages that last in hours, not just minutes, so my suggestion is to make refresh-token rotation safe to retry by using an idempotency key with a longer recovery window.
When Refresh1 is exchanged for Refresh2, the authorization server should store the issued response against the idempotency key. For the next 12–24 hours, if the client retries the same refresh request with the same idempotency key, the server should return the already-issued Refresh2 response instead of treating Refresh1 as malicious reuse or issuing another token.
This retry path should only recover the result of the original refresh. It should not extend the lifetime of Refresh1, create another token, or revive an old generation. Once Refresh2 is used to issue Refresh3, retries of Refresh1 with the old idempotency key should be rejected as stale.
The goal is to make refresh-token rotation resilient to ambiguous failures such as timeouts, 5xx responses, or lost responses, while preserving the security guarantees of refresh-token rotation.
We’ve just had a few errors too, luckily the app we are testing on doesn’t have any background processes.
We also retry the same request immediately either.
@TerenceShopify such errors aren’t acceptable, how do we recover access to these stores without having to ask the merchant to open the app? As you can appreciate, merchants won’t always respond immediately, some merchants may not be technical enough to know what’s going on as their developers have setup apps for them and is difficult to get them to action these requests.