← All tasks

SSO bounce-chain — preserve attempted path through /cafe/login placeholder LOCAL · GATE 1

Diagnosed live from a user screen-recording (2026-05-22): clicking NIX Cafe on the Commerce launchpad after an idle period — or after our regression sweep — bounced through /cafe/login and ended back on the launchpad with the original destination lost. Verified the root cause against deployed code: the (authed)/layout.tsx redirect to /login didn't pass a ?redirect= param, so the Cafe placeholder forwarded to Commerce with ?redirect=/ — which the H5.8 guard correctly (per its rules) treats as not-a-product-path and sends to launchpad.

7/7 local · 6 files touched · ~25 LOC · no migration · no deps. Middleware injects x-nix-pathname on every passed-through request; new loginRedirectUrl() helper in lib/auth.ts reads it; 5 server-side redirect("/login") callsites updated to redirect(await loginRedirectUrl()). The Cafe placeholder app/login/login-form.tsx already honors the ?redirect= query — once the path threads through to it, Commerce's H5.8 guard kicks in and the login form renders for a sibling-product redirect.

Files touched

nix-cafe/middleware.tsInject x-nix-pathname on every NextResponse.next(...) via new pass() helper
nix-cafe/lib/auth.tsNew loginRedirectUrl() export; signIn stub uses it
nix-cafe/lib/authz.tsrequirePermission — 2 callsites (no-session + no-accessible-page fallback)
nix-cafe/lib/permissions.server.tsrequirePermission — no-session callsite
nix-cafe/app/(authed)/layout.tsxDefensive !session guard — the primary bug site from the video
nix-cafe/app/(pos-fullscreen)/pos/register/[configId]/page.tsx!session?.user guard at top of register page

Local checks — 7/7

What's NOT exercised in Gate 1. The deepest failure path — valid JWT signature + middleware passes + auth() rejects on sid mismatch → (authed)/layout.tsx redirects via the new helper — needs a forged JWT cookie, which requires JWT_SECRET that isn't in nix-cafe/.env.local (cookies are minted by the backend at :3001; local cafe dev just verifies them). Plus the local backend dev server (start-dev.sh) isn't running this session, so a full backend-mint → cafe-verify round-trip isn't available either. Gate 2 prod is the right place — we rotate tenant_users.active_session_token via SQL on a logged-in lumiere-coffee owner to force the deep-auth-fail path, then assert the redirect chain end-to-end.

Also: an earlier check probed GET /cafe/login directly via page.request and hit a 500 — the AGENTS.md-documented stale-dev-server gotcha for middleware-bypass routes on a long-running Next dev server. The placeholder route's CODE is unchanged by this slice; only its callers (middleware injection + server-side ?redirect=-building callsites) changed. Both are covered above. Dropping that probe rather than restarting the dev server since it's not load-bearing.

Before / after — the bounce chain

Before vs After — server-side bounce path preserves the user's attempted destinationSide-by-side trace from "click NIX Cafe" through to "lands on intended page after re-auth"

Gate 2 plan

Push nix-cafe commit to karouna-dev → CF Pages auto-deploys ~90s. Then run a Playwright prod test against lumiere-coffee that:

Plus 51/51 regression sweep. Risk: low — the change is server-side redirect URL plumbing, no DB, no API contract, no UI rendering. Most likely failure mode is a dev-only TypeScript regression we already cleared with tsc --noEmit.