Embedded app keeps reloading / exit-iframe to /auth when access token is expired – how to avoid full page reload?

Hi everyone,

I’m building an embedded Shopify app and I’m having an issue where the app automatically reloads the whole page and redirects to an exit-iframe URL whenever the access token or session is expired.

I’ll describe the behavior and what I want to achieve, and I’d really appreciate any guidance or best practices to handle this properly.


1. Current behavior (auto reload / exit-iframe)

When I open my app from the Shopify admin, if the access token is expired, the app doesn’t just fail the API call. Instead, the whole page “F5 reloads” and I see a URL like this:

https://admin.shopify.com/store/``<my-store>/apps/<my-app>/auth/exit-iframe?exitIframe=%2Fauth%3Fshop%3D<my-shop>.myshopify.com%26host%3D...

Decoded, that’s basically:

.../auth/exit-iframe?exitIframe=/auth?shop=<my-shop>.myshopify.com&host=...

So what’s happening is:

  • The app (or the Shopify auth middleware) detects that the session / access token is invalid or expired.

  • It triggers an exit-iframe redirect to /auth at the top-level.

  • The browser reloads the entire app, goes through the OAuth/auth flow again, and then comes back.

From the user’s perspective, this looks like a sudden full-page reload just because the token expired.


2. What I would like to achieve

I understand that for initial OAuth and some security constraints (SameSite cookies, 3rd-party iframe, etc.), Shopify needs to use exit-iframe to run the auth flow in a top-level context.

However, I would like to:

  1. Avoid this full-page reload / exit-iframe as much as possible in normal usage.

  2. Preferably, when tokens expire, handle it in a way that doesn’t always kick the user out to /auth in a disruptive way.

In other words:

  • I’m OK with doing a top-level redirect for the very first install or when absolutely required.

  • But I don’t want the app to reload and go through /auth every time a token/session expires, especially for common actions like just opening the app from the admin.


3. What I think is happening under the hood

From what I understand (please correct me if I’m wrong):

  • Shopify App Bridge / the auth middleware sees that there is no valid session or the access token has expired.

  • It then automatically responds with a redirect to /auth.

  • App Bridge detects this and uses the exit-iframe mechanism to open /auth in the top-level window.

  • /auth starts the OAuth flow again to get a new token.

  • After that, it redirects back to the embedded app.

So from a high level, this is probably “correct” according to the standard templates, but it leads to a UX where the app keeps reloading when tokens expire.


4. My questions

I’m looking for best practices or recommended configuration to avoid or minimize this behavior:

  1. Should I be using an offline access token for most of my backend API calls, so that I don’t need to re-authenticate the user frequently?

    • For example, using an offline token (non-expiring or expiring with refresh token) stored in my database, and:

      • Only using the OAuth flow when the app is first installed or when refresh fails.

      • Calling the Admin API / Partner API from the backend using the offline token, so the frontend doesn’t have to re-auth every time.

  2. Should I fully switch to session tokens (JWT) for embedded app authentication, instead of relying on traditional cookie sessions?

    • So the frontend gets a short-lived session token on every load (via App Bridge),
      and the backend validates that JWT and uses a long-lived offline access token for API calls.

    • In that flow, when would exit-iframe still be necessary? Only for the first install / when no offline token exists for that shop?

  3. How should I configure my auth middleware so that:

    • It doesn’t redirect to /auth on every request,

    • It only triggers /auth (and therefore exit-iframe) when:

      • There is no stored offline token for that shop, or

      • The offline token + refresh token are truly invalid / revoked?

  4. Is there any official Shopify example or documentation that shows:

    • A complete embedded app setup using:

      • Session tokens for frontend → backend auth, and

      • Offline access tokens for Shopify API calls,

    • In a way that avoids repeated exit-iframe redirects when the user simply opens the app in admin?


5. My tech stack

  • Store: <my-store>.myshopify.com

  • App: Embedded app

  • Tech stack: [please fill in: Node.js / Next.js / PHP / Laravel / Ruby / etc.]

  • Auth libraries used: [please fill in: e.g. @shopify/shopify-app-express, shopify-api-node, custom OAuth, etc.]

If it helps, I’m happy to share snippets of my:

  • /auth and /auth/callback routes, and

  • Auth middleware where I check the session / shop and potentially call the OAuth flow again.


6. Summary

  • Issue: When the user opens the embedded app and the access token/session is expired, the app automatically reloads the whole page and redirects via exit-iframe to /auth to get a new token.

  • Goal: Reduce or avoid this disruptive reload behavior, by configuring auth correctly (offline tokens, session tokens, middleware logic, etc.).

  • Ask: Any official guidance, examples, or recommended patterns from Shopify or the community to handle this case cleanly?

Thanks in advance for any advice, links, or code examples!