fix(portal-shell): send withCredentials on /me so the session cookie crosses SPA→BFF in dev #114
Reference in New Issue
Block a user
Delete Branch "fix/portal-shell/auth-me-with-credentials"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Manual smoke after PR #113 surfaced a dev-only bug: after
/auth/callbackthe BFF correctly sets theportal_sessioncookie and redirects to the SPA, but the SPA's next call to/api/auth/mecomes back 401 with nocookie:header at all. The user lands "back at the portal" but the header still shows "Sign in".Root cause. Angular's
HttpClientviawithFetch()inheritsfetch's defaultcredentials: 'same-origin'. In dev,localhost:4200(SPA) →localhost:3000(BFF) is cross-origin (different ports), so the browser drops the session cookie on the way out. SameSite=Lax is a red herring: both URLs share the registrable domain, so the cookie is still same-site — what was missing was opting the fetch into credentials.Fix. Per-call
withCredentials: trueon the /me request. Only /me needs cookies today; login/logout are full-page navigations throughwindow.location, which the browser hydrates with cookies regardless. A globalHttpInterceptorwill be the right abstraction once other authenticated BFF endpoints exist — premature for one consumer.BFF side was already correct.
enableCors({ credentials: true })inmain.ts. Nothing to change.A new spec pins
withCredentials === trueon the /me request so a future refactor can't silently drop the flag and reintroduce the bug.Test plan
pnpm nx test feature-auth→ 9/9 pass (was 8 before; +1 spec pinning the credentials flag).pnpm nx test portal-shell→ 32/32 pass.pnpm nx lint feature-auth portal-shell→ clean.pnpm nx build portal-shell→ clean.manual smoke surfaced the bug: the callback wrote the session and set the portal_session cookie correctly, but the spa's next /me call came back 401 with no cookie header at all. root cause: angular's HttpClient via withFetch() inherits fetch's default `credentials: 'same-origin'`. localhost:4200 → localhost:3000 is cross-origin (different ports), so the session cookie is dropped on the way out — the bff never sees it. samesite=lax was a red herring: localhost:4200 and localhost:3000 share the registrable domain, so the cookie is still same-site; what was missing was opting the fetch into credentials. fix is per-call: only /me needs cookies today. login/logout are full-page navigations through window.location, which the browser hydrates with cookies regardless. a global HttpInterceptor will land when other authenticated bff endpoints exist — premature for one consumer. bff side was already wired: enableCors({ credentials: true }) in main.ts. nothing to change there. a spec pins withCredentials=true on the /me request so a future refactor can't silently drop the flag and reintroduce the bug.