{"record":{"id":"759ce7bfc47e8c21","repo":"nextauthjs/next-auth","slug":"csrf-token-was-missing-during-an-action-action","errorCode":null,"errorMessage":"CSRF token was missing during an action ${action}","messagePattern":"CSRF token was missing during an action (.+?)","errorType":"exception","errorClass":"MissingCSRF","httpStatus":null,"severity":"error","filePath":"packages/core/src/lib/actions/callback/oauth/csrf-token.ts","lineNumber":59,"sourceCode":"      // If this is a POST request and the CSRF Token in the POST request matches\n      // the cookie we have already verified is the one we have set, then the token is verified!\n      const csrfTokenVerified = isPost && csrfToken === bodyValue\n\n      return { csrfTokenVerified, csrfToken }\n    }\n  }\n\n  // New CSRF token\n  const csrfToken = randomString(32)\n  const csrfTokenHash = await createHash(`${csrfToken}${options.secret}`)\n  const cookie = `${csrfToken}|${csrfTokenHash}`\n\n  return { cookie, csrfToken }\n}\n\nexport function validateCSRF(action: AuthAction, verified?: boolean) {\n  if (verified) return\n  throw new MissingCSRF(`CSRF token was missing during an action ${action}`)\n}\n","sourceCodeStart":41,"sourceCodeEnd":61,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/lib/actions/callback/oauth/csrf-token.ts#L41-L61","documentation":"Auth.js throws MissingCSRF when a state-changing auth action (signin, signout, callback) arrives without the CSRF token cookie that was set when the session/page was rendered. The library requires the csrfToken cookie value to match the csrfToken POSTed in the form body to prevent cross-site request forgery against the auth endpoints.","triggerScenarios":"POSTing to /api/auth/callback/*, /api/auth/signout, or /api/auth/signin/* without the authjs.csrf-token (next-auth.csrf-token) cookie, or with a body/form value that does not include the csrfToken returned by GET /api/auth/csrf.","commonSituations":"Calling auth endpoints with fetch/axios or curl without first fetching /api/auth/csrf and sending credentials: 'include'; browser blocking cookies (SameSite/Secure/HTTPS mismatch, cross-subdomain requests); custom sign-in pages that forget the hidden csrfToken input; server-side redirects that drop cookies; reverse proxies stripping Set-Cookie headers.","solutions":["Fetch GET /api/auth/csrf first, then POST the csrfToken value in the request body while sending cookies (credentials: 'include' in browsers)","Verify cookies are enabled and not blocked: check Secure/SameSite attributes match HTTPS deployment and that the request is same-site, or configure cookies.cookies.sessionToken/partner options in AuthOptions","If using a custom login form, include the csrfToken as a hidden field (NextAuth useSession/csrf helpers) in the POSTed form data","Check reverse proxy/CDN configuration (e.g. Cloudflare, Vercel rewrites) is not stripping the Set-Cookie header that delivers the CSRF cookie","Clear stale cookies and retry: an expired/rotated CSRF cookie can mismatch after secret changes; ensure NEXTAUTH_SECRET/AUTH_SECRET is stable across instances"],"exampleFix":"// before\ncsrfToken: \"useSecureCookies\" ? undefined : null,\n\n// after\nconst res = await fetch(`${baseUrl}/api/auth/csrf`, { credentials: 'include' });\nconst { csrfToken } = await res.json();\nawait fetch(`${baseUrl}/api/auth/signin/credentials`, {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n  credentials: 'include',\n  body: new URLSearchParams({ csrfToken, username, password }),\n});","handlingStrategy":"try-catch","validationCode":"const r = await fetch(`${baseUrl}/api/auth/csrf`, { credentials: 'include' });\nconst { csrfToken } = await r.json();\nif (!csrfToken) throw new Error('No CSRF token available');","typeGuard":"function hasCsrf(x: unknown): x is { csrfToken: string } {\n  return typeof x === 'object' && x !== null && typeof (x as any).csrfToken === 'string' && (x as any).csrfToken.length > 0;\n}","tryCatchPattern":"try {\n  await signIn(provider, options, formData);\n} catch (e) {\n  if (e instanceof MissingCSRF || /CSRF token was missing/.test(String(e))) {\n    // refresh CSRF token via GET /api/auth/csrf and retry once with credentials: 'include'\n  }\n}","preventionTips":["Always fetch /api/auth/csrf before POSTing to any auth action endpoint","Send cookies with every auth request (credentials: 'include')","Keep AUTH_SECRET stable so CSRF cookies remain valid across deploys","Check SameSite/Secure cookie attributes match your deployment (HTTPS vs localhost)","Verify proxies/CDNs do not strip Set-Cookie headers"],"tags":["csrf","security","cookies","http"],"backgroundTag":"missing-csrf-token","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}