Skip to content

fix: harden Next.js AuthKit skill against Server Component cookie violations#13

Merged
nicknisi merged 2 commits intomainfrom
fix/nextjs-auth-hardening
Mar 31, 2026
Merged

fix: harden Next.js AuthKit skill against Server Component cookie violations#13
nicknisi merged 2 commits intomainfrom
fix/nextjs-auth-hardening

Conversation

@nicknisi
Copy link
Copy Markdown
Member

@nicknisi nicknisi commented Mar 30, 2026

Summary

When running workos install on a Next.js B2B app, the installer agent could generate auth UI with three failure modes:

  1. Server Component cookie violation — generating nav-auth.tsx as a Server Component calling getSignInUrl(), which sets PKCE cookies. Next.js 16 forbids cookie modification during render.
  2. [object Object] redirect — SDK's actions.js calls getAuthorizationUrl() which returns { url, sealedState }, not a string.
  3. OAuth state mismatchsealedState discarded when using raw getAuthorizationUrl(), so PKCE cookie never set.

Bugs 2-3 are SDK bugs (out of scope here). Bug 1 is fixed by strengthening the skill reference that guides the installer agent.

Changes

Reference guide (workos-authkit-nextjs.md)

Step 8 rewrite — the old Step 8 ended with "See README for the recommended approach", which was too vague for the agent to follow reliably. The new version:

  • Adds an explicit NavAuth client component example using useAuth() + refreshAuth({ ensureSignedIn: true }) with the correct import from @workos-inc/authkit-nextjs/components
  • Splits guidance into "Server Components (safe)" vs "Shared nav/header auth UI (preferred)" sections
  • Adds "Critical auth URL gotchas" section warning against raw getAuthorizationUrl() (returns object, not string; drops PKCE cookie)
  • Adds verification checks 4-5 that rg for unsafe patterns in generated code
  • Adds error recovery sections for [object Object] redirect and OAuth state mismatch

Eval cases (authkit-nextjs.yaml)

  • authkit-nextjs-protected — removed getSignInUrl from expected methods (it shouldn't appear in server component answers) and added it as an anti-pattern for server component usage. Added form action={await getSignInUrl()} anti-pattern.
  • authkit-nextjs-nav-auth-pkce (new) — regression case that directly encodes the three-bug scenario. Tests for AuthKitProvider, useAuth, refreshAuth, ensureSignedIn, and penalizes getSignInUrl in server components, raw getAuthorizationUrl, window.location.href = auth.signInUrl, and discarded sealedState.

Scorer regression test (eval-scorer.spec.ts)

Compares a broken implementation (the exact bug pattern) against the fixed implementation. Broken scores ≤60, fixed scores ≥80, and the broken pattern triggers security_issue error category.

Eval results

Case With skill Without Delta
authkit-nextjs-nav-auth-pkce 91% 65% +26% ±1
authkit-nextjs-protected 84% 72% +12% ±6.5

Companion PR: workos/cli#110 (NextjsGrader structural check)

…lations

- Rewrite Step 8 UI Integration with explicit NavAuth client component
  pattern using useAuth() + refreshAuth({ ensureSignedIn: true })
- Add useAuth import from @workos-inc/authkit-nextjs/components
- Warn against raw getAuthorizationUrl() usage (returns object, not string)
- Add error recovery sections for [object Object] and OAuth state mismatch
- Add verification checks for unsafe auth URL patterns
- Add anti-pattern checks to authkit-nextjs-protected eval case
- Add authkit-nextjs-nav-auth-pkce regression eval case
- Add scorer regression test (broken: 59, fixed: 98)

Addresses Alexander Southgate's friction log: getSignInUrl() in Server
Components, [object Object] redirect, and PKCE state mismatch.
@nicknisi nicknisi merged commit 21853e2 into main Mar 31, 2026
2 checks passed
@nicknisi nicknisi deleted the fix/nextjs-auth-hardening branch March 31, 2026 20:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant