Skip to content

[Feature] Add token exchange auth strategy and hooks support to shopify-app-express#3097

Open
mrmarufpro wants to merge 2 commits intoShopify:mainfrom
mrmarufpro:main
Open

[Feature] Add token exchange auth strategy and hooks support to shopify-app-express#3097
mrmarufpro wants to merge 2 commits intoShopify:mainfrom
mrmarufpro:main

Conversation

@mrmarufpro
Copy link

@mrmarufpro mrmarufpro commented Mar 13, 2026

WHY are these changes introduced?

Fixes #630 — adds token exchange authentication support to shopify-app-express, bringing it to parity with the Remix package.

Shopify's token exchange API reduces flickering and OAuth redirects for embedded apps. While this was already supported in the Remix package, Express apps had no way to use it. This PR implements token exchange for Express behind the unstable_newEmbeddedAuthStrategy future flag so existing apps are unaffected.

WHAT is this pull request doing?

  • future config option — adds a feature flag system (unstable_newEmbeddedAuthStrategy, expiringOfflineAccessTokens) with logging for disabled flags
  • Token exchange middleware (perform-token-exchange.ts) — when unstable_newEmbeddedAuthStrategy is enabled and a Bearer token is present in the Authorization header, validateAuthenticatedSession performs a token exchange instead of redirecting to OAuth
  • ensureInstalled shortcut — when the token exchange strategy is on, ensureInstalledOnShop skips the session check and goes straight to embedding/loading the app
  • hooks.afterAuth — async callback invoked after both OAuth and token exchange flows, deduplicated via IdempotentPromiseHandler to prevent double-firing on concurrent requests
  • registerWebhooks({session}) — convenience method on ShopifyApp wrapping api.webhooks.register
  • expiringOfflineAccessTokens flag — threads the flag into auth.callback and auth.tokenExchange calls
  • ensureOfflineTokenIsNotExpired helper — proactively refreshes offline tokens nearing expiry in the standard OAuth path
  • Docs updated for shopifyApp, validateAuthenticatedSession, auth, and a new token-exchange guide added
  • Tests added for all new code paths

Type of change

  • Minor: New feature (non-breaking change which adds functionality)

Checklist

  • I have used pnpm changeset to create a draft changelog entry (do NOT update the CHANGELOG.md files manually)
  • I have added/updated tests for this change
  • I have documented new APIs/updated the documentation for modified APIs (for public APIs)

@mrmarufpro
Copy link
Author

I've been running these changes in a production embedded app by patching the package locally, and everything is working as expected. Token exchange flows complete cleanly, afterAuth fires correctly (including on concurrent requests, thanks to IdempotentPromiseHandler), and ensureInstalledOnShop behaves properly under the unstable_newEmbeddedAuthStrategy flag.

I did need a couple of minor tweaks to get it wired up in my app, but nothing that points to a problem with the implementation itself — just the usual integration details. Overall the behavior is solid and consistent with how the Remix package handles token exchange.

Happy to share more specifics if it helps the review.

@mrmarufpro
Copy link
Author

Hi @lizkenyon, I’m requesting a review.

mrmarufpro and others added 2 commits March 18, 2026 13:06
… support

Implements the `unstable_newEmbeddedAuthStrategy` future flag which enables
token exchange-based authentication for embedded apps, bypassing the OAuth
redirect flow when a Bearer session token is present. Also adds:

- `future` config option with feature flag support and logging
- `hooks.afterAuth` callback invoked after OAuth and token exchange flows
- `registerWebhooks` convenience method on the ShopifyApp object
- `idempotentPromiseHandler` to deduplicate concurrent hook invocations
- `expiring` offline access token support in auth callback and token exchange
- `ensureOfflineTokenIsNotExpired` helper to refresh tokens nearing expiry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for token exchanger in Express

1 participant