Repository navigation
fix: start page authentication in the callback route - #482
Conversation
Fixes DAX-3330. Preserve page-level guards without render-time cookie writes or speculative PKCE cookies.
|
nicknisi
left a comment
There was a problem hiding this comment.
Review
Looks good — approving.
Right fix for the Next 16 "cookies only in Server Action / Route Handler" failure when withAuth({ ensureSignedIn: true }) runs in a Server Component. Moving PKCE setup onto the existing handleAuth() callback (via sealed __authkit_start routing data) is clean, and the prefetch/RSC short-circuit is important so verifier cookies aren't created by Link prefetch.
Routing payload validation (purpose tag, return-path origin check, no OAuth-state substitution) and the new auth-start.spec.ts coverage look solid. README guidance to keep getSignInUrl / getSignUpUrl in Route Handlers is correct.
Local verification (this branch, workspace-linked examples/next)
pnpm test— 430/430 passed; lint / typecheck / build clean (Node 22)- Signed-out document GET
/account→ 307 to/callback?__authkit_start=…, no Set-Cookie, no 500 - Document navigation to that start URL → 307 to WorkOS authorize + one
wos-auth-verifier-*cookie (Max-Age=600) - RSC/prefetch GET to the same start URL → 200 empty body, no Set-Cookie
Didn't complete a live OAuth round-trip (dummy credentials); the signed-out start path that was 500ing is fixed.
Non-blocking: sealed __authkit_start query strings can get long — worth a quick thought on reverse-proxy URL limits in prod, but I wouldn't block on it.
|
No further product change from this review. The approved fix conflicts with |
Integrate current callback failure cleanup and issuer validation without changing the accepted page-guard PKCE flow. Resolve README terminology and update the renamed sign-in route anchor.
Treat Purpose and Sec-Purpose prefetch tokens with parameters as passive requests. Cover Chrome prerender and whitespace variants at the existing callback boundary without changing ordinary document PKCE behavior.
Fixes DAX-3330 — Linear issue
Problem and discovery
Anonymous Ask WorkOS QA generated the documented Next.js integration: default
authkitProxy()pluswithAuth({ ensureSignedIn: true })in a Server Component. We copied all six generated application files, includingAuthKitProvider, into a real Next 16.2.1 app with published AuthKit 4.3.1, Node SDK 10.13.0, and React 19.2.4.Fresh
/returned 200,/dashboardreturned 500 twice, and the explicit/loginRoute Handler returned 307. The dashboard error was:The SDK README and canonical docs recommend this pattern. This was an upstream SDK/context mismatch, not an invented API or an indexing bug.
Adjacent-commit checks in the same full Next fixture confirmed
4c3f27bredirects successfully and ebef6e7 (#388) fails when PKCE/state becomes mandatory. The later cookie-deferral change #432 is not the cause and is not reverted.Minimal reproduction
In a normal Next 16 App Router app with its root layout/provider, use:
Set
WORKOS_API_KEY,WORKOS_CLIENT_ID, a 32+ characterWORKOS_COOKIE_PASSWORD, andNEXT_PUBLIC_WORKOS_REDIRECT_URI=http://127.0.0.1:3000/callback, then run the app and request:curl -i -H 'Accept: text/html' http://127.0.0.1:3000/dashboardDummy credentials suffice to reproduce the failure; do not follow the eventual WorkOS redirect for this local check.
Change
code/staterequests retain callback validation, including malformed mixed requests. OAuth state cannot substitute for routing data. Schema failures use a generic error rather than exposing decrypted input through logs oronError. Per-flow cookie names and existing callback checks/cleanup remain unchanged; cookie options use the configured public URI, not an internal proxy origin.getSignInUrl()/getSignUpUrl()helpers in Route Handlers or Server Actions, not during rendering. No Ask-specific override or public getter API expansion.Verification
8a1a3b5eea3cedbae8ae78b6a59c1a328d5ec6fc, treeb675aded98c8da3c476453e43e01a1f80ef35364, integrated with current main3acb7e1c. Node 22.22.3 and 24.21.0 format, zero-warning lint, source/test typecheck and build pass; 461 tests pass on each Node version. Exact-head CI and all five required checks pass. Final Greptile completion remains a pre-merge gate; no prior-head result is substituted./dashboardnow returns a local 307 with no verifier cookie; its document start returns 307 with one matching cookie. Verified state/cookie equality, SHA-256 challenge/verifier equality, return path/query and byte-exact configured callback URI, including127.0.0.1and encoded query values.Linkprefetch/click in Chrome: no pre-click verifier cookie or authorization request; callback RSC request returns 200/no cookie, followed by document navigation returning 307/one cookie. The final unchanged six-application-file fixture passes 11 checks covering document/Next/browser preload handling, exact callback URI and return query, cached routing/sign-up hints, concurrent PKCE, callback security, Route Handler and Server Action.905e8ccf: Chrome reuses empty callback 200 and makes no fresh document request. Final SDK 503/no-store/no verifier cookie instead yieldsPrefetchFailedNon2XX; real navigation then reaches document 307, one fresh cookie and independently validated PKCE at a loopback authorization sink. The proxy passes through actual SDK status/headers/body unchanged. DevTools disables detached prerendering, so full detached or omnibox prerender activation is not claimed. No hosted login or token exchange occurred. The final fixture was reconstructed from the documented six files; the original September fixture was unavailable.Release and documentation handoff
The owner has authorized merge and delivery. This source PR still does not itself publish the fix: use the normal Release Please release PR and npm OIDC publish workflow, then qualify the actual registry tarball/source and unchanged Next fixture. A separate reviewed
workos/workosdocs PR must regenerate the AuthKit README through the canonical transform, align the guide/proxy examples and record the actual first fixed npm version before normal docs deployment. A complete SDK-source reindex is also required. Source merge/indexing alone is not npm or canonical-docs delivery. No package version is claimed until the actual release is published and qualified; no merge, release, docs deploy or index mutation has occurred as of this final source verification.