Skip to content

Ask AI

Ask anything about Destesi — setup, products, APIs.

Powered by Claude. Answers may be wrong — always verify against the docs.

OAuth passthrough

One pre-registered OAuth callback serves every ephemeral preview URL. Google, GitHub, Microsoft, and Slack all work out of the box with standard Auth.js apps — no per-PR redirect-URI registration.

OAuth providers require a pre-registered redirect_uri (exact-match). Previews run on ephemeral hosts — prev-abc.your-workspace.preview.destesi.io, prev-def…, and so on. Registering one per preview is impractical; using a wildcard isn’t supported by most providers.

Two pieces cooperate:

  1. The runner sets AUTH_REDIRECT_PROXY_URL on your app to the central Destesi base ending in /v1/oauth. Auth.js v5 appends /callback/<provider> to it, so the redirect_uri your app sends to the provider is …/v1/oauth/callback/<provider> — the one URL you pre-register with each provider. The overlay does not rewrite redirect_uri itself (the two OAuth legs have to agree, and the token-exchange leg isn’t a redirect the overlay can intercept).
  2. The overlay proxy (which sits in front of every preview) intercepts outbound 302s to known OAuth authorize endpoints and replaces the state query param with a destesi-signed envelope carrying the original app state plus (preview_id, provider, callback_path, nonce, exp).

After the provider authenticates, it returns to the central API, which unwraps the envelope, validates the signature and expiry, and 302s the browser back to the preview’s real /api/auth/callback/<provider> with the original app state restored.

Provider Authorize host & path
Google accounts.google.com/o/oauth2/v2/auth
GitHub github.com/login/oauth/authorize
Microsoft login.microsoftonline.com/common/oauth2/v2.0/authorize
Slack slack.com/oauth/v2/authorize

Matching is host-exact plus path-exact (or a subpath of the listed path). Other providers — and authorize URLs on other paths — pass through unchanged.

For a typical Auth.js v5 / NextAuth app:

  • Set trustHost: true in your Auth.js config so it honors the X-Forwarded-* headers the overlay sets.
  • Do not set NEXTAUTH_URL in the preview env. With trustHost: true, Auth.js reads the preview’s own forwarded host — setting NEXTAUTH_URL pins one URL and breaks previews.
  • Your app’s real callback path must follow Auth.js v5 convention: /api/auth/callback/<provider>. Custom paths are supported via the preview’s oauth_json field.

Overlay OAuth interception is disabled if DESTESI_OAUTH_STATE_SECRET is unset at preview startup. The overlay logs a warning and passes OAuth redirects through unchanged — your app receives the original state and must then handle provider callbacks at its own URL (requires per-preview redirect-URI registration, not recommended).

  • The signed state envelope is HMAC-signed with DESTESI_OAUTH_STATE_SECRET; tampering fails validation and the callback is rejected.
  • Envelopes carry a nonce + expiry so a replay won’t authenticate a different preview.
  • The central API verifies the preview still exists and is not deleted before emitting the final redirect.
  • The app’s original state is passed through unchanged (it’s just wrapped), so your app’s own state verification still works end-to-end.