{"record":{"id":"eebe515e13af87b1","repo":"nextauthjs/next-auth","slug":"invalid-state","errorCode":null,"errorMessage":"Invalid state","messagePattern":"Invalid state","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/lib/actions/callback/oauth/checks.ts","lineNumber":200,"sourceCode":"    return { cookie, value }\n  },\n  /**\n   * Returns state if the provider is configured to use state,\n   * and clears the container cookie afterwards.\n   * An error is thrown if the state is missing or invalid.\n   */\n  use: useCookie(\"state\", \"state\"),\n  /** Decodes the state. If it could not be decoded, it throws an error. */\n  async decode(state: string, options: InternalOptions) {\n    try {\n      options.logger.debug(\"DECODE_STATE\", { state })\n      const payload = await decode<EncodedState>({\n        secret: options.jwt.secret,\n        token: state,\n        salt: encodedStateSalt,\n      })\n      if (payload) return payload\n      throw new Error(\"Invalid state\")\n    } catch (error) {\n      throw new InvalidCheck(\"State could not be decoded\", { cause: error })\n    }\n  },\n}\n\nexport const nonce = {\n  async create(options: InternalOptions<\"oidc\">) {\n    if (!options.provider.checks.includes(\"nonce\")) return\n    const value = o.generateRandomNonce()\n    const cookie = await sealCookie(\"nonce\", value, options)\n    return { cookie, value }\n  },\n  /**\n   * Returns nonce if the provider is configured to use nonce,\n   * and clears the container cookie afterwards.\n   * An error is thrown if the nonce is missing or invalid.\n   * @see https://openid.net/specs/openid-connect-core-1_0.html#NonceNotes","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/lib/actions/callback/oauth/checks.ts#L182-L218","documentation":"state.decode throws the plain Error \"Invalid state\" when JWT-decoding the state token with options.jwt.secret and the encoded-state salt returns no payload. It is immediately wrapped into InvalidCheck(\"State could not be decoded\"), so developers normally see that outer message with this as cause.","triggerScenarios":"The state query parameter on the callback cannot be decoded into an EncodedState payload — expired/tampered JWT, wrong AUTH_SECRET, or a state value not produced by this app.","commonSituations":"Multi-instance deployments with different secrets; state JWT from a previous deploy/secret; manually edited callback URLs; very old in-flight sign-in attempts after a secret rotation.","solutions":["Set a single explicit AUTH_SECRET shared across all instances and stable across deploys.","Have the user restart the sign-in flow to generate fresh state.","Inspect error.cause for JWT verification details (signature/expiry).","Don't hand-edit or reuse old callback URLs."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (!process.env.AUTH_SECRET) throw new Error(\"AUTH_SECRET required for state signing\")","typeGuard":null,"tryCatchPattern":"try {\n  const session = await auth()\n} catch (e) {\n  if (e?.message?.includes(\"State could not be decoded\")) {\n    // redirect user to start sign-in again\n  }\n}","preventionTips":["Use a persistent shared AUTH_SECRET","Treat state as single-use: always restart the flow on failure","Never modify callback URLs manually"],"tags":["oauth","state","jwt-decode","csrf"],"backgroundTag":"oauth-state-invalid","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}