---
title: Token Exchange killed the OAuth redirect
url: https://honeybound.co/blog/token-exchange-killed-oauth-redirect
date: 2026-04-22
summary: Shopify Token Exchange and Managed Installation change OAuth app setup. See what to delete, what to build, and which migration gotchas matter.
tldr: Shopify Token Exchange changes the app install flow. Modern embedded apps should remove legacy OAuth redirects and rely on managed installation patterns.
tags: shopify, auth, embedded-apps
---

There's a tab open in your browser right now that loads
`https://your-app.com/auth?shop=...&hmac=...&timestamp=...`. If you wrote that
route after January 2025, you wrote dead code.

The new model — Managed Installation plus Token Exchange — has been the
recommended path for embedded Shopify apps for almost a year. Most tutorials
still teach the redirect flow because Shopify hasn't taken the old docs down.
They should. The migration is shorter than people think, and the result is
simpler in every direction.

## What changed

Managed Installation moved the install + consent screen *into Shopify itself*.
You declare the scopes your app needs in `shopify.app.toml`, push it with
`shopify app deploy`, and Shopify handles the install UX. No redirect. No
state nonce. No HMAC-on-querystring dance.

App Bridge — the JS SDK that runs inside the Admin iframe — mints a session
token (a JWT) on every request from the embedded UI. Your backend takes that
JWT and exchanges it for an offline access token via the Token Exchange
endpoint. The offline token is what you use for every subsequent Shopify API
call.

End state: no `/auth` route, no `/auth/callback`, no nonces, no install-flow
cookies, no post-install redirect logic. Just middleware.

## What you delete

- The `/auth` install URL builder
- The `/auth/callback` handler
- The HMAC verifier on the redirect query string (you still need HMAC on
  webhooks — don't delete that one)
- The cookie-based pre-auth session
- The post-install redirect URL builder
- The `state` nonce store

Most of this lives in one or two files. Deleting it is satisfying.

## What you write instead

Middleware. About 80 lines of Go. The shape:

1. Pull the JWT out of the `Authorization: Bearer …` header.
2. Validate the signature against your app secret.
3. Verify the audience and issuer claims — both must match the shop domain
   making the request.
4. Look up an offline token for that shop in Redis.
5. If miss: call Token Exchange with the JWT as `subject_token`, cache the
   returned offline token under `{app}:token:{shop_domain}`.
6. Hand the offline token to the request context.

That's it. One round-trip per uncached shop, then everything is local.

## Gotchas nobody warns you about

**Session tokens expire after 60 seconds.** App Bridge auto-refreshes them on
the client. Server-side webhook handlers don't have App Bridge. They still
need HMAC verification — do not delete that path.

**`invalid_subject_token` is a soft error.** Token Exchange returns it when a
shop has uninstalled mid-flight, or when the JWT is past its 60-second window.
Treat it as a 401 and let the client retry. Treating it as a 500 will fill
your error tracker with noise during normal uninstalls.

**The offline token can be revoked out-of-band.** A merchant can uninstall and
reinstall in the same minute. Your cache won't know. The right invalidation
trigger is "next failed API call returns `invalid_token`" — not the install
webhook, which can race.

**Local dev still uses the live Shopify issuer.** Even when you're tunneling
to localhost, the JWT issuer is the production Shopify domain. Don't hardcode
issuer checks against your tunnel URL.

## When NOT to migrate

If your app is non-embedded — lives outside the Admin iframe and serves its
own dashboard — OAuth redirect is still the right tool. App Bridge isn't
there to mint session tokens, so there's nothing to exchange. Our event
pipeline app stays on OAuth redirect for exactly this reason. Embedded apps
are the ones that benefit.

---

Recurrabee and searchabee both run this pattern in production today —
[see /work](/work) for what they actually do. The migration took a couple of
afternoons each. The auth code that's left is shorter, easier to reason about,
and stops being something you have to think about.

## Key takeaways

- Managed Installation shifts install authorization away from custom OAuth redirect handling.
- Token Exchange gives embedded apps a safer way to obtain app access tokens.
- The migration is mostly deleting old redirect assumptions and tightening app-session logic.

## FAQ

### Does Shopify still require OAuth redirects for embedded apps?

Modern managed-installation apps can use Token Exchange instead of maintaining a full legacy OAuth redirect flow.

### What should be removed during a Token Exchange migration?

Remove old redirect handlers, callback-state assumptions, and install-path logic that conflicts with Shopify managed installation.

### What is the biggest Token Exchange migration risk?

The main risk is keeping mixed legacy and modern flows alive, which can create broken installs or confusing session behavior.

