使用 PKCE 的 MCP OAuth 2.1:通过 7 个步骤保护您的代理服务器
2026-03-15 MCP 规范使 OAuth 2.1 + PKCE 成为代理服务器的授权标准。 交付的七个步骤:PRM 元数据、动态客户端注册、范围设计和使用代码进行令牌验证。
2026-03-15 MCP规范锁定OAuth 2.1,以PKCE作为授权标准 远程 MCP 服务器。 环境变量中的 API 密钥在第一天仍然有效,但注册表, 当用户使用 Claude Desktop、Cursor、VS Code Copilot 和 Windsurf 时,它们都更喜欢 OAuth 支持的服务器 浏览集成。 如果您的服务器仍然要求在配置文件中提供长期持有者,您 正在把一大块分配留在桌面上。
困难的部分不是 OAuth 本身;而是 OAuth 本身。 这是 MCP 身份验证流程组成的五个小规格 一起:OAuth 2.1 (RFC 9700)、PKCE (RFC 7636)、动态客户端注册 (RFC 7591)、 资源指示器 (RFC 8707) 和受保护的资源元数据。 每一个都很小; 接线 这是团队陷入困境的地方。 这是按顺序排列的路径。
步骤 1:提供受保护的资源元数据文档
PRM 文件告诉客户端您的授权服务器在哪里、您接受哪些范围以及什么
要放入的资源标识符 aud 宣称。 举办于
/.well-known/oauth-protected-resource 与您的 MCP 端点位于同一源:
这 authorization_servers list 是发现跃点。 客户获取您的 PRM,
按照 AS 元数据文档的第一个条目,并从那里构建授权 URL。
除非您运行联盟,否则请将列表保留为一个条目; 多个发行人使客户感到困惑
规范中没有任何内容需要它。
步骤2:发布授权服务器元数据
您的身份提供商(Auth0、Okta、Clerk、Cloudflare Access 或自托管 Hydra)提供服务
AS 元数据位于 /.well-known/oauth-authorization-server。 MCP 客户端使用它
了解授权和令牌端点、支持的授权类型以及 JWKS 位置
用于令牌验证:
规范要求的三个字段: code_challenge_methods_supported 必须包括
S256; grant_types_supported 必须包括
authorization_code 和 refresh_token;
registration_endpoint 如果您支持动态客户端,则必须在场。 想念任何一个
Claude Desktop 会在安装过程中将服务器标记为不合规。
步骤3:在客户端生成PKCE对
PKCE 是 20 行客户端代码,它杀死了授权代码拦截类 攻击。 生成32个随机字节,将它们base64url编码为验证器,SHA-256验证器 进入挑战,并发送带有授权请求的挑战:
这 resource 参数(RFC 8707)是大多数实现中遗漏的一个。 没有
它,为您的 MCP 服务器铸造的令牌可以针对任何其他信任该服务器的 API 进行重放
同一发行人; 有了它, aud 声明将令牌固定到您的资源标识符
没有其他东西接受它。
第四步:用代码兑换代币
重定向回来后,客户端将代码加上原始验证者 POST 到令牌中 端点。 授权服务器重新计算验证者的 SHA-256 并将其与 存储的挑战; 如果它们匹配,您将获得一个访问令牌:
将刷新令牌存储在安全存储中(钥匙串、Windows 凭据管理器、Linux libsecret)并在交换成功时从会话存储中删除验证程序。 访问 代币的存活时间为 5 至 60 分钟; 刷新令牌的寿命更长,但仍应轮换使用。
步骤 5:验证每个 MCP 请求上的承载令牌
Streamable HTTP 使令牌验证变得简单:每个 HTTP 请求都携带
Authorization 标头,因此您的 MCP 服务器之前会在中间件中验证它
调度工具调用。 获取 JWKS 一次,将其缓存,并验证发行者、受众和
每次调用都会过期:
捕获真正错误的三个声明: iss 固定发行人;
aud 固定资源(防止跨资源重放);
exp 捕获陈旧的令牌。 如果没有这些,请勿接受代币; “我验证了
签名”与“我验证了声明”不同。
第 6 步:在其注释声明的范围内控制每个工具
OAuth 2.1 减范围设计为您提供二进制访问:客户端可以调用每个工具,或者 没有。 MCP 注释系统通过让每个工具声明其范围来缩小这一差距 需要。 处理程序在调用时读取注释和令牌范围:
将破坏性作用域和只读作用域分开。 授予的用户 tools:read 到
运行周报不应该运行 send_email 同样的道理。
克劳德桌面和光标在同意屏幕中显示请求的范围,因此拆分使得
用户体验诚实地了解客户可以做什么。
第7步:支持动态客户端注册
动态客户端注册允许 MCP 客户端在您的授权服务器上自行注册
无需人工填写表格。 光标或克劳德桌面发布注册请求,
收到一个 client_id,并立即运行 OAuth 流程:
这是将您的 MCP 服务器从“将 API 密钥粘贴到配置文件中”移动到 “单击光标中的连接并授予访问权限。” 如果您的服务器是公共的,那么这项工作是值得的; 可跳过 如果您只向一小部分已知客户发货。
验证端到端的全流程
一旦各部分就位,完整的 MCP 工具调用看起来就像任何其他经过身份验证的 HTTP 请求:
如果你看到 401 和 WWW-Authenticate: Bearer resource_metadata="...",
客户端知道在哪里发现您的身份验证设置并重新运行流程。 该标题是
握手,使静默令牌刷新和撤销后重新连接成为可能。
将 PRM URL 放入 WWW-Authenticate 每个 401 响应的标头。 MCP
规范使其成为规范的发现提示; 看到未注释的 401 回退的客户端
向用户询问 API 密钥,这正是 OAuth 2.1 试图取代的流程。
范围设计备忘单
| 范围 | 封面 | 默认补助金 |
|---|---|---|
tools:read |
列出可用工具,阅读说明 | 始终在同意的情况下授予 |
tools:invoke:safe |
幂等、只读工具调用(查找、解析) | 已获得每个用户的同意 |
tools:invoke:destructive |
变异工具调用(发送电子邮件、创建订单) | 需要明确的每次会话同意 |
resources:read |
对公开资源的只读访问 | 按资源模式授予 |
prompts:read |
列出并读取服务器定义的提示 | 经同意后授予 |
要点
- OAuth 2.1 需要 PKCE。 不是一个可有可无的东西; 每个授权代码流都带有一个 验证者和挑战,否则不符合规范。
-
PRM 于
/.well-known/oauth-protected-resource是入口点。 客户端从该 URL 发现您的身份验证设置; 跳过它,客户端将无法自动配置。 -
使用
resource参数(RFC 8707)。 固定令牌受众 到您的 MCP 服务器,以便泄漏的令牌无法针对其他 API 进行重放。 - 验证发行人、受众、有效期、范围。 签名检查单独让 跨资源重播通过。
-
分割破坏范围。
tools:read,tools:invoke:safe, 和tools:invoke:destructive给用户 同意他们期望从操作系统权限获得的用户体验。 - 动态客户端注册解锁零配置安装。 支付 实施成本一次; 每个新的 MCP 客户都会永远受益。
Botoi 的托管 MCP 服务器位于 api.botoi.com/mcp 运行相同的模式。 浏览 MCP 设置文档 适用于 Claude Desktop、Claude Code、Cursor、VS Code 和 Windsurf 配置。 对于 JWT 签名 上面的中间件使用的验证原语,请参阅 JWT API 端点 在交互式文档中。
FAQ
- 当代理不是浏览器时,为什么要为 MCP 使用 PKCE?
- PKCE(代码交换证明密钥)将授权代码绑定到只有发起客户端知道的一次性加密秘密。 在 MCP 上下文中,攻击者不是恶意浏览器扩展; 它是流氓代理或漂浮在终端日志中的被盗授权代码。 PKCE是指如果没有原始代码验证者,截取的代码将无法兑换。 OAuth 2.1 要求每个授权代码流(包括机密客户端)都使用 PKCE,因此 MCP 仅遵循规范。
- 什么是受保护资源元数据文档?
- PRM 文档是在 /.well-known/oauth-protected-resource 中提供的 JSON 文件,它告诉 OAuth 客户端授权服务器所在的位置、资源接受的范围以及要在 aud 声明中放入的资源标识符。 MCP 授权规范添加了 PRM,因此 MCP 客户端无需带外配置即可发现您的身份验证设置。 客户端获取 PRM,按照authorization_servers URL 访问 AS 元数据,运行 OAuth dance,并使用有效的承载令牌到达您的 MCP 服务器。
- 我需要动态客户端注册吗?
- 对于向许多客户端公开的公共 MCP 服务器,是的。 动态客户端注册 (RFC 7591) 允许 MCP 客户端在您的授权服务器上自行注册、接收 client_id 并在一次往返中启动 OAuth 流程。 如果没有它,每个用户都必须在仪表板中手动创建应用程序,然后才能连接 Claude 或 Cursor。 对于内部或白名单集成,预配置的 client_id 仍然有效。
- 会话期间不记名令牌位于何处?
- 在每个 MCP 请求的授权标头中。 Streamable HTTP 使这一切变得干净; 每个请求都携带令牌,您的服务器在分派工具调用之前会在中间件中验证它。 客户端持有的刷新令牌的短期访问令牌(5 到 60 分钟)可最大限度地减少泄漏日志行的爆炸半径。 切勿将令牌嵌入 URL 中; 日志和代理定期捕获 URL。
- MCP 工具范围与 OAuth 范围相比如何?
- MCP 依赖于基于角色的授权:令牌携带诸如工具:读取、工具:调用:安全或工具:调用:破坏性等范围,并且各个工具注释声明它们需要哪些范围。 范围与 OAuth 范围一对一映射,因此您可以使用 REST API 已有的相同范围设计。 新的部分是 MCP 端的工具级注释; 它们使授权决策在工具注册表中可见,而不仅仅是在处理程序代码中。
开始使用 botoi 构建
150+ 个 API 端点,涵盖查询、文本处理、图片生成和开发者工具。免费套餐,无需信用卡。