Skip to content

fix(auth): scope session cookies to registrable domain + diagnostic reasons - #840

Merged
tran-christian merged 1 commit into
mainfrom
claude/debug-pending-cookies-FNAlV
Apr 22, 2026
Merged

fix(auth): scope session cookies to registrable domain + diagnostic reasons#840
tran-christian merged 1 commit into
mainfrom
claude/debug-pending-cookies-FNAlV

Conversation

@tran-christian

@tran-christian tran-christian commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Fifth attempt at the OAuth session-cookie bug. Builds on #835's x-forwarded-host redirect fix with the one thing it didn't touch: cookie scope. Plus adds conclusive diagnostics so the next failing attempt (if any) pinpoints the branch without needing server logs — removeConsole: true strips them.

Root cause hypothesis

PR #835's author confirmed in DevTools on www.omshub.org that the PKCE -code-verifier cookie lands but sb-<ref>-auth-token[.0/.1] do not, despite Supabase returning /token 200. x-forwarded-host corrects the redirect target, but the Set-Cookie response is still emitted by whichever host answered the function invocation — on Vercel that can be an internal LB. @supabase/ssr 0.8 writes cookies with no Domain attribute, so they become Host-only and bind to that internal host. The browser then navigates to www.omshub.org and never sends them.

What changed

app/auth/callback/route.ts:

  • Explicit cookie Domain derived from x-forwarded-host (falling back to origin), with port and leading www. stripped — e.g. Domain=omshub.org. Session stays valid on both www.omshub.org and the bare apex regardless of which host the response came from. localhost / IP literals are skipped (some browsers reject Domain=localhost; Host-only is correct for local dev).
  • Distinguishable failure reasons. Error path now redirects to /?error=auth_callback_error&reason=<one of: no_code | exchange_failed | no_session | no_pending_cookies> (with a truncated message= for exchange errors). Makes prior "something failed" silence legible.
  • Short-lived auth_debug cookie on success (60s, non-HttpOnly) encoding { host, usedForwardedHost, cookieDomain, pendingCookieCount }. If this cookie is missing in DevTools → Cookies → omshub.org after sign-in, we know the whole response was rejected; if it's present but sb-*-auth-token* aren't, the bug is inside @supabase/ssr itself.
  • Split early-return helpers (failureRedirect, clearVerifierAndReturn) to dedupe the error paths.

app/page.tsx + app/_components/AuthErrorNotification.tsx:

  • Forward new reason and message search params into the Mantine error toast so they surface in the UI, not just the URL.

Why prior attempts didn't land

Domain scoping is the last piece. If after this deploy the session still doesn't stick, the auth_debug cookie + reason= param tell you exactly which of the four remaining failure modes to investigate without digging through Vercel logs.

Test plan

  • Deploy preview builds clean
  • Sign in on www.omshub.org with Google → lands on / with session (welcome toast), no ?error=
  • DevTools → Cookies for omshub.org: auth_debug present, sb-<ref>-auth-token (+ chunks .0/.1 if large) present with Domain=omshub.org
  • Navigate to bare omshub.org in a new tab — still signed in (proves the scope widening)
  • Sign in on a preview deployment → no ?error=; auth_debug has cookieDomain: "<preview>.vercel.app"
  • Local dev (pnpm dev) sign-in via magic link still works (Host-only path)
  • Existing proxy test (src/lib/supabase/__tests__/proxy.test.ts) still passes
  • Failure path: hit /auth/callback directly in a browser — lands on /?error=auth_callback_error&reason=no_code with matching toast

Rollback

Revert the commit — all changes are additive to app/auth/callback/route.ts, app/page.tsx, and app/_components/AuthErrorNotification.tsx. No schema, config, or env var changes.

@vercel

vercel Bot commented Apr 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
website Ready Ready Preview, Comment Apr 22, 2026 2:49am

@tran-christian
tran-christian marked this pull request as draft April 22, 2026 02:22
@supabase

supabase Bot commented Apr 22, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project ilwqylsdqacxmfkisclx because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

…easons

Session cookies stamped after exchangeCodeForSession are Host-only by
default in @supabase/ssr 0.8. On Vercel the response host can be an
internal LB, so Set-Cookie attaches to that host even though Location
points at www.omshub.org — and the browser never sends the session back.

#835 fixed the redirect target via x-forwarded-host but did not touch
the cookie scope; the reporter confirmed in DevTools that the PKCE
code_verifier lands while sb-<ref>-auth-token[.0/.1] does not. Explicitly
set Domain to the registrable domain (omshub.org, derived from the public
host with www. stripped) so the session is valid on both www and apex
regardless of which host answered the request. Skipped for localhost /
IP literals — Host-only is correct there and some browsers reject
Domain=localhost.

Also split the error redirect into four distinguishable ?reason= values
(no_code, exchange_failed, no_session, no_pending_cookies) and add a
60-second non-HttpOnly auth_debug cookie on success so the next sign-in
attempt is conclusive from DevTools alone — removeConsole: true strips
server logs in prod.
@tran-christian
tran-christian force-pushed the claude/debug-pending-cookies-FNAlV branch from 5902e61 to 6f951fc Compare April 22, 2026 02:48
@tran-christian
tran-christian marked this pull request as ready for review April 22, 2026 02:49
@tran-christian
tran-christian merged commit da6bcde into main Apr 22, 2026
17 checks passed
@tran-christian
tran-christian deleted the claude/debug-pending-cookies-FNAlV branch April 22, 2026 02:49
tran-christian added a commit that referenced this pull request Apr 22, 2026
…841)

@supabase/ssr 0.8.0 has an SSR race condition where the GoTrue client
auto-initializes asynchronously and can hijack the cookie-writing path
after exchangeCodeForSession. The symptom in our setup: /token returns
200, data.session is populated, but the SSR client never invokes the
cookies.setAll callback — so session cookies never reach the response.
Our diagnostic patch (#840) surfaced this exact branch as
?reason=no_pending_cookies.

Fixed upstream in 0.8.1 via skipAutoInitialize: true (PR #131).
Bumping to latest 0.10.2 picks up that fix plus 0.10.0's setAll cache
headers, which prevent proxies/CDNs from caching auth responses.

@supabase/supabase-js bumped to ^2.104.0 to satisfy the new peer
requirement (ssr 0.10.2 needs ^2.102.1). No breaking changes in either
package in the traversed range — createServerClient, createBrowserClient,
exchangeCodeForSession, getSession, getUser, onAuthStateChange all
retain their signatures.

No source changes — package.json + pnpm-lock.yaml only.
tran-christian added a commit that referenced this pull request Apr 22, 2026
…ug cookie (#842)

With the root cause fixed in #841, the browser-side auth_debug cookie
from #840 has served its purpose — it was one-off scaffolding to prove
the pipeline carries cookies end-to-end. Replacing it with server-side
error logs in Vercel's runtime log viewer: zero client footprint, no
leaked deployment details to analytics/replay scripts, full context
when things actually go wrong.

next.config.js: removeConsole in prod now uses { exclude: ['error'] }
so console.error survives compilation. console.log/warn/info/debug are
still stripped. DEBUG_AUTH=1 continues to disable stripping entirely
for local `pnpm build && pnpm start` repro.

app/auth/callback/route.ts:
- Shared `diag` object captures the same fields the auth_debug cookie
  carried (forwardedHost, pendingCookieCount, pendingCookieNames,
  requestCookieNames, publishableKeyPrefix, origin, hasSession,
  hasUser) plus SDK-side signals.
- Every abnormal branch logs `[auth/callback] reason=<branch>` with
  `diag` to console.error. exchange_failed also includes the SDK
  message + status. no_code is not logged (crawler noise).
- auth_debug cookie + debugPayload construction removed.
- DEBUG_AUTH-gated console.log block removed — its content is a subset
  of `diag` and only fires now when something is actually wrong.
- Unused `oauth_error` option removed from failureRedirect's union.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant