Skip to content

feat(oauth): add headless activation flow and fix redirect allowlist - #50

Open
ddpie wants to merge 1 commit into
mainfrom
feat/headless-activate-and-redirect-allowlist
Open

feat(oauth): add headless activation flow and fix redirect allowlist#50
ddpie wants to merge 1 commit into
mainfrom
feat/headless-activate-and-redirect-allowlist

Conversation

@ddpie

@ddpie ddpie commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

English

Why

The standard OAuth flow requires the browser and the MCP client on the same machine: the client listens on a loopback port and the authorization code is redirected there. When the agent runs on a remote host and the browser is on a laptop, that redirect lands on the wrong machine and authorization cannot complete without SSH port forwarding.

Separately, the redirect allowlist rejected VS Code entirely. VS Code submits four redirect URIs in one dynamic client registration — two loopback forms plus https://vscode.dev/redirect and https://insiders.vscode.dev/redirect — and rejecting any single entry fails the whole registration. Those two hosted brokers hand the flow back to the originating editor instance, which is what makes VS Code work over Remote-SSH, Dev Containers and Codespaces without port forwarding.

Changes

  • add /activate, a self-service authorization route with no client redirect_uri and no PKCE. Feishu returns to this service over HTTPS and /callback renders the resulting 30-day MCP token for the user to copy into their client's request headers. No port forwarding, no SSH tunnel, no client-side capability required.
  • accept the two VS Code hosted redirect brokers in both /register and /authorize.
  • accept the full RFC 8252 §7.3 loopback set — localhost, all of 127.0.0.0/8, and [::1] — instead of only localhost and 127.0.0.1.
  • render the activation token only in the response body, never in a URL, redirect or log, with Cache-Control: no-store and Referrer-Policy: no-referrer.
  • document the remote/headless path in both language versions of the client connection guide, including the per-client alternatives for Claude Code, Codex and VS Code.

The activation route grants no new authority: /token already issues 30-day tokens over the standard flow, and revocation is unchanged because mcp-middleware re-reads the user's Feishu token from Secrets Manager on every request, so revoking a user invalidates every token they hold.

The widening of the allowlist is strictly limited to the loopback block and those two broker hosts. Non-allowlisted https hosts, broker-lookalike subdomains, brokers over plain http, and non-loopback http hosts all stay rejected.

Verification

  • ./scripts/test.sh — 34 test files, 716 tests passed (24 new)
  • new tests were proven non-vacuous: reverting the allowlist fix fails 6 of them, removing the activation token page fails 4
  • the minted token is verified in-test using the exact derivation and comparison mcp-middleware performs, so a token that would not authenticate cannot pass
  • assertions cover that the token never appears in a redirect, in any response header, or alongside the single-use Feishu authorization code, and that the ordinary success page still carries no token

中文

背景

标准 OAuth 流程要求浏览器与 MCP 客户端在同一台机器上:客户端监听 loopback 端口,授权码被重定向到那里。当 Agent 运行在远程主机、浏览器在笔记本上时,该重定向会落到错误的机器,必须靠 SSH 端口转发才能完成授权。

另一个独立问题是 redirect allowlist 完全拒绝了 VS Code。VS Code 在一次动态客户端注册中提交四个 redirect URI —— 两个 loopback 形式,加上 https://vscode.dev/redirecthttps://insiders.vscode.dev/redirect —— 其中任意一项被拒都会导致整次注册失败。这两个托管跳板负责把流程交还给发起它的编辑器实例,正是 VS Code 在 Remote-SSH、Dev Containers 和 Codespaces 下无需端口转发的原因。

改动

  • 新增 /activate 自助授权入口,不带客户端 redirect_uri,也不使用 PKCE。飞书通过 HTTPS 回到本服务,/callback 渲染出有效期 30 天的 MCP token 供用户复制到客户端请求头。无需端口转发、SSH 隧道或任何客户端特殊能力。
  • /register/authorize 均接受 VS Code 的两个托管跳板域。
  • 接受 RFC 8252 §7.3 完整 loopback 集合 —— localhost、整个 127.0.0.0/8 以及 [::1] —— 取代原先只认 localhost127.0.0.1
  • 激活令牌仅出现在响应正文,绝不进入 URL、重定向或日志,并附带 Cache-Control: no-storeReferrer-Policy: no-referrer
  • 在中英文两版客户端连接文档中补充远程/无头授权路径,并列出 Claude Code、Codex 与 VS Code 各自的替代方案。

激活入口不授予任何新权限:/token 在标准流程下本来就签发 30 天 token;吊销语义也未变,因为 mcp-middleware 每次请求都会重新从 Secrets Manager 读取该用户的飞书 token,撤销用户即使其持有的所有 token 立即失效。

allowlist 的放宽严格限定在 loopback 段与上述两个跳板域。非白名单 https 域、形似跳板的子域、走明文 http 的跳板域,以及非 loopback 的 http 域,均保持拒绝。

验证

  • ./scripts/test.sh —— 34 个测试文件、716 条测试通过(新增 24 条)
  • 已验证新测试非空转:回退 allowlist 修复会导致其中 6 条失败,移除激活令牌页会导致 4 条失败
  • 测试中使用 mcp-middleware 完全相同的密钥派生与比对方式校验签发的 token,因此无法通过鉴权的 token 不可能通过测试
  • 断言覆盖令牌不出现在重定向、任何响应头中,也不与一次性飞书授权码同时出现,并确认原有成功页仍不携带令牌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant