state_mismatch

请求中的 state 参数与 cookie 中的 state 参数不匹配。

什么是 state_mismatch?

当 OAuth 流程开始时,会生成一个唯一的 state 值并存储在 cookie 中。 当用户从 OAuth 提供商返回时,会将该 state 值与回调中提供的值进行比较。 如果它们不匹配,请求将被拒绝,以防止未经授权的访问。

此检查存在的目的是为了防止 OAuth 流程中的 CSRF(跨站请求伪造)和重放攻击—— 基本上,就是确保访问 /api/auth/callback 端点的回调请求确实属于 启动该流程的同一浏览器会话。

常见原因

  • 回调时 cookie 未设置或无法读取(在 .vercel.app 预览域或跨域问题中常见)。
  • 应用和回调路由之间的 cookie 域名或路径不匹配。
  • 浏览器阻止了第三方 cookie(尤其是在 Safari / iOS 上)。
  • 你在一个标签页启动 OAuth 流程,但在另一个标签页完成(cookie 上下文不同)。
  • 预览环境与生产环境域名不一致(例如,preview.myapp.commyapp.com)。

如何解决

使用固定域名

  • 最好的解决办法是为你的应用和回调路由使用固定域名。
  • 避免使用 .vercel.app 子域——浏览器会将其当作公共后缀,因此无法跨子域共享 cookie。
  • 你可能在身份验证配置中设置了自定义的 cookie 属性,导致此问题。
  • 检查浏览器设置或隐私模式中是否阻止了 cookie。
  • 确认你在同一浏览器会话中启动并结束 OAuth 流程。

如果你知道自己在做什么,可以通过在身份验证配置中 将 account.skipStateCookieCheck 选项设置为 true 来跳过 state cookie 校验。

请注意,这存在安全风险,仅当你明确了解其影响时才启用。

生产环境调试

进入你的生产网站,使用浏览器的开发者工具 → 应用程序 → Cookie,确认:

  • 在跳转前状态 cookie 是否被设置。
  • OAuth 提供商重定向回来时,该 cookie 是否仍然存在。