OIDC csrf_detected 可能会掩盖用户取消/同意拒绝 - 文档可以澄清日志检查

接续自 OIDC 登录通过 Discourse iOS 应用偶尔在回调时失败并显示 csrf_detected 的讨论:

大家好,

这是关于我之前关于从 iOS 应用内浏览器发起的 OIDC 登录失败的帖子的后续观察。该讨论侧重于由 WKWebView Cookie 隔离引起的确定性 csrf_detected 失败,这些失败现在似乎已得到充分理解和预期。

这个链接的主题是关于操作员清晰度,而不是错误。


观察

在调查一系列 OIDC 登录失败时,我注意到 Discourse 中相同的表面错误:

/auth/oidc/callback → /auth/failure?message=csrf_detected

可能对应于多个根本不同的上游原因,具体取决于 IdP 返回的内容。

仅从应用程序 UI 来看,这些情况是无法区分的。差异只能通过检查“管理”→“日志”→“env / params”来查看。


实践中观察到的示例(Azure / Entra ID)

除了应用内浏览器 Cookie 丢失之外,我还观察到 Entra ID 明确返回结构化错误的那些回调,例如:

用户拒绝同意

error=consent_required
error_description=AADSTS65004: User declined to consent to access the app

用户取消登录

error=access_denied
error_subcode=cancel

在这两种情况下:

  • Azure 成功识别了用户
  • 用户明确选择不继续(拒绝/取消)
  • Discourse 接收到回调
  • 流程最终解析为 /auth/failure?message=csrf_detected

从 Discourse 的角度来看,这是正确且安全的行为——状态无法验证或完成——但根本原因与缺少会话 Cookie 非常不同。


对操作员的重要性

如果没有检查日志的 env/params,看到重复的 csrf_detected 失败的管理员可能会合理地假设:

  • Cookie 损坏
  • SameSite 配置错误
  • 移动浏览器问题
  • IdP 不稳定

……但实际上,其中一些失败仅仅是用户选择不同意或取消了 Microsoft 的提示。

只有当您已经知道要检查原始日志有效负载时,这种区别才会变得清晰。


建议(仅限文档/UX)

我不是建议对 OmniAuth 或 CSRF 处理进行任何行为更改。

如果文档或故障排除指南明确指出以下内容可能会有所帮助:

  • csrf_detected 可以是多个上游 IdP 结果的最终错误
  • 包括明确的用户操作,如取消或拒绝同意
  • 管理员应检查“管理”→“日志”→“env / params”以区分这些情况

这将使操作员更容易:

  • 正确诊断登录失败
  • 避免不必要的配置更改
  • 并向用户提供准确的指导(“您已取消/拒绝同意”与“您的浏览器阻止了 Cookie”)。

背景

为求清晰:这与链接主题中讨论的已确认的 iOS 应用内浏览器问题是分开的。在这种情况下,IdP 从未达到用户同意的阶段,而在本例中,IdP 会明确报告用户意图。

除非检查日志,否则两者在 UI 级别看起来都很相似。


感谢阅读——发布此内容主要是为了提高文档的清晰度/为在学生众多的环境中运行 OIDC 的其他人提供一个数据点,因为这些情况经常发生。

如果需要,我很乐意提供匿名示例。