[Bug]: OIDC SSO deep-link redirect is lost after login; callback returns 302 Location: /

使用 OIDC SSO 登录的 n8n 自托管实例,在未登录状态下打开受保护深链(如 /form/... 或 /workflow/...)时,登录完成后会被强制跳回 /home/workflows,原始目标页丢失。优先排查方向是后端 OIDC 回调是否具备持久化并还原 return_target 的

快速结论:使用 OIDC SSO 登录的 n8n 自托管实例,在未登录状态下打开受保护深链(如 /form/… 或 /workflow/…)时,登录完成后会被强制跳回 /home/workflows,原始目标页丢失。优先排查方向是后端 OIDC 回调是否具备持久化并还原 return_target 的事务逻辑,而不是前端按钮或代理配置。

适用环境:n8n 2.26.3,Node.js v24.15.0,PostgreSQL,Docker 运行于 Alpine 3.22,self hosted,执行模式为 main(默认)。认证方式为 OIDC SSO。

最快修复方案:暂无确认的一步修复方案。Issue 讨论中给出的方向是把原始跳转目标绑定为 OIDC 事务属性(与 state 一次性关联),在回调时消费事务后再重定向,但这属于设计建议,尚未有已发布版本验证。

注意事项:不要直接把未校验的绝对 URL 塞进回调做跳转,否则可能形成开放重定向。Issue 中已排除 IdP state 丢失、角色映射失败、SameSite 配置、代理/入口清洗以及特定路由问题,因此继续调这些方向大概率无效。

问题场景

在 n8n 自托管实例上启用 OIDC SSO 后,用户以未登录状态点击外部发来的深链(例如 Slack、Jira、邮件中的表单链接 /form/example-form?issue=EXAMPLE-123 或工作流链接 /workflow/<id>)。n8n 会先把请求拦截并跳转到 /signin?redirect=<target>,用户点击 SSO 登录并在 IdP 完成认证后,本应回到原始目标页。

问题出现在 OIDC 流程返回 n8n 之后:前端 SSO 按钮没有把 redirect 参数传给后端;即使手动把 redirect 传给后端登录端点 /rest/sso/oidc/login?redirect=<target>,回调完成后仍然忽略该参数。

报错原文

[Bug]: OIDC SSO deep-link redirect is lost after login; callback returns 302 Location: /

302 Location: /

原因分析

最可能的原因:n8n 后端 OIDC 流程缺少状态管理逻辑,无法在认证前保存深链目标、在回调时读取并还原。报告作者明确说明这不是单纯的前端 UI 问题,因为直接把 redirect 传给后端登录端点后,callback 依然返回硬编码的 302 Location: /。

Issue 中已逐项排除以下可能原因:IdP 未回传 state、认证/角色映射失败、SameSite Cookie 被丢弃、代理/Ingress 清洗参数、特定路由差异。因此这些方向不再是主要怀疑对象。

讨论中的社区建议进一步指出,正确做法应把返回目标作为 OIDC 一次性事务属性绑定到 state,而不是作为独立参数穿过 callback。这样才能同时满足“保留用户原始意图路径与查询串”和“只允许跳回 n8n 允许过的目标”两个不变量。

环境排查

  • 确认 n8n 版本:Issue 中为 2.26.3。
  • 确认 Node.js 版本:Issue 中为 v24.15.0。
  • 确认数据库为 PostgreSQL。
  • 确认运行方式为 Docker,基础镜像 Alpine 3.22,执行模式 main(默认),self hosted。
  • 确认 OIDC SSO 已启用,并确认 IdP 侧 state 回传正常。
  • 确认 N8N_LOG_LEVEL=debug 下能看到 OIDC 客户端配置与 SSO 角色解析完成且无报错。
  • 确认访问路径为受保护深链(/form/… 或 /workflow/…),而非公开页面。

解决步骤

  1. 先按 Issue 的两个测试复现:正常 UI 流程(打开深链 → /signin?redirect=… → SSO → 观察落点)与直接后端测试(手动访问 /rest/sso/oidc/login?redirect=%2Fworkflow%2F<workflow-id>)。两者都落到 /home/workflows 即复现成功。
  2. 抓取 OIDC 登录到 callback 的完整请求链,确认回调响应头确实是 302 Location: /,而不是被 IdP 或代理改写。
  3. 确认前端 SSO 按钮是否把 redirect 传给后端;Issue 证据显示它没有传。
  4. 即使手动给后端 login 端点补上 redirect,回调仍忽略它,说明需要后端在认证事务中保存目标。可优先尝试的方向是:在创建认证事务时记录规范化后的相对 return_target,并将其引用编码进 OIDC state,callback 校验 state 后一次性消费该事务并跳转到存储的目标。
  5. 若无法改动后端(例如等待官方修复),可作为临时绕过手段:登录完成后由用户手动返回原深链;或在外部通知里同时附上目标链接,方便认证后再次点击。此绕过未在 Issue 中验证。

验证方法

修复后应验证以下回归场景是否全部通过:

  • /workflow/<id> 深链登录后回到该工作流。
  • /form/<path>?issue=EXAMPLE-123 登录后回到该表单,且查询串完整保留。
  • 过期或被重放的 state 应回退到默认页,不执行重定向。
  • 外部目标(如 https://evil.example)应被拒绝或回退,避免开放重定向。
  • 同时发起两个登录事务时,各自应回到自己的目标,而不是共用同一个全局/会话级 redirect 槽位导致串号。

只要其中任一场景未通过,说明修复尚未完整。

参考来源

n8n-io/n8n #35017

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29298

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注