SEP-2207:OIDC 风格的刷新令牌指南
社区译文;来源: MCP 29affa6b
| 字段 | 值 |
|---|---|
| SEP | 2207 |
| 标题 | OIDC 风格的刷新令牌指南 |
| 状态 | Final |
| 类型 | 标准跟踪 |
| 创建日期 | 2026-02-04 |
| 作者 | Wils Dawson (@wdawson) |
| 发起人 | Paul Carleton (@pcarleton) |
| PR | #2207 |
摘要
本提案为 MCP 实现提供有关签发和请求刷新令牌的指导,尤其适用于授权服务器支持 offline_access scope 的情况。offline_access scope 源自 OIDC,但任何 OAuth 2.1 授权服务器都可以采用这一机制,让客户端明确请求刷新令牌。本 SEP 阐明授权服务器和 MCP 客户端使用该模式时的预期行为。
动机
MCP 的授权机制基于 OAuth 2.1,但许多实际部署使用的授权服务器还实现了 OpenID Connect(OIDC)。纯 OAuth 与 OIDC 的一个关键区别在于刷新令牌的处理方式:
- 在纯 OAuth 2.1 中,没有让客户端明确请求刷新令牌的标准机制。授权服务器根据客户端能力(例如客户端元数据中的
refresh_tokengrant type)及其自身策略决定是否签发刷新令牌。 - 在 OIDC(以及采用此约定的授权服务器)中,除 OAuth 的逻辑之外,还存在
offline_accessscope,允许客户端明确请求刷新令牌。
这在 MCP 生态系统中造成了几个问题:
客户端没有请求刷新令牌:主要 MCP 客户端(Cursor、Claude、VS Code 等)没有通过
offline_accessscope 明确请求刷新令牌,因为它们不知道授权服务器是否支持、期望或要求这一 scope。资源服务器不应指定
offline_access:offline_accessscope 不是资源特定的 scope,而是客户端与授权服务器之间的事项。将其包含在WWW-Authenticate标头的scope参数或受保护资源元数据的scopes_supported中,在语义上并不正确,因为这意味着资源要求刷新令牌,而资源永远不会提出这种要求。授权服务器可能行为不一致:处理授权码授权时,不同授权服务器向不同客户端签发刷新令牌的行为可能不同,尤其是在客户端没有将
refresh_token指定为 grant type,或没有请求offline_accessscope 的情况下。互操作性缺口:缺少此指导时,各实现可能表现不一致,导致糟糕的用户体验(频繁重新认证)或安全问题(向无法安全存储刷新令牌的客户端签发令牌)。
规范
MCP 客户端要求
希望使用刷新令牌并且能够安全存储它们的 MCP 客户端 SHOULD 遵循以下指导:
声明能力:客户端 SHOULD 在其
grant_types客户端元数据中包含refresh_token,以表明其支持刷新令牌。补充 scope:当客户端希望获得刷新令牌,并且授权服务器元数据的
scopes_supported字段包含offline_access时,客户端在向授权服务器发出授权请求前,MAY 将offline_accessscope 加入来自资源服务器的 scope 列表。不作保证:客户端 MUST NOT 假定声明支持能力或请求
offline_access就一定会收到刷新令牌。授权服务器仍可根据其策略自行决定。
MCP 服务器(资源服务器)要求
作为 OAuth 2.0 受保护资源的 MCP 服务器:
SHOULD NOT 在
WWW-Authenticate标头的scope参数中包含offline_access,因为刷新令牌不是资源要求。SHOULD NOT 在受保护资源元数据的
scopes_supported中包含offline_access,因为它不是资源特定的 scope。
理由
为何不要求在 401 响应中包含 offline_access?
offline_access scope 与资源特定的 scope 有本质区别。它表达客户端希望获得长期访问,而不是资源提出的要求。根据 OAuth 2.1 第 5.3.1 节,WWW-Authenticate 中的 scope 属性表示“访问所请求资源时,访问令牌所需的 scope”。由于资源不要求 offline_access,将其包含在内在语义上并不正确。
为何检查客户端元数据中的 grant type?为何不总是签发刷新令牌?
OAuth 2.1 要求客户端注册其支持的 grant type。不支持 refresh_token grant 的客户端可能:
- 无法安全存储刷新令牌
- 没有使用刷新令牌的机制
向此类客户端签发刷新令牌会浪费授权服务器资源(跟踪永远不会使用的令牌),并且在令牌泄露时可能带来安全风险。
为何允许使用 offline_access 作为替代信号?
一些授权服务器只有在明确请求 offline_access 时才会签发刷新令牌,无论它们是完全符合 OIDC,还是仅采用这一约定。支持这种模式可为这类部署提供兼容路径。客户端可以检查授权服务器元数据的 scopes_supported 中是否存在 offline_access,从而检测支持此约定的授权服务器,并相应调整行为。
考虑过的替代方案
强制资源响应包含
offline_access:已否决,因为这会错误表达资源的要求,并形成反模式。始终签发刷新令牌:已否决,因为这会忽略客户端能力和授权服务器安全策略。
制定单独的 OIDC 专用规范:已否决,选择采用同时适用于纯 OAuth 和 OIDC 部署的统一方法。
为授权服务器提供指导:已否决,选择依赖 OAuth 和 OIDC 规范提供相关指导,因为具体做法可能不同。
向后兼容性
本提案完全向后兼容:
- 已经请求
offline_access的客户端可继续工作 - 已经检查客户端能力的授权服务器可继续工作
- 不要求 MCP 服务器进行任何更改
- 本指导是加法性的,不改变现有的必需行为
不遵循本指导的实现可能出现非最优行为(缺少刷新令牌或不必要地签发令牌),但仍能正常工作。
安全影响
正面安全影响
降低令牌泄露风险:不向未声明支持能力的客户端签发刷新令牌,可以降低长期令牌被不安全存储的风险。
纵深防御:风险评估步骤使授权服务器可以灵活实施额外的安全控制。
注意事项
客户端元数据可能并不充分:由于客户端元数据是自行声明的,恶意行为者可以注册一台声称支持
refresh_tokengrant 的客户端,以获取长期令牌。授权服务器 MAY 使用风险评估步骤(参见“规范”)施加额外限制,例如域名允许列表、信誉检查或验证要求,而不是在决定是否签发刷新令牌时仅依赖客户端元数据声明。Scope 注入:客户端添加
offline_access时,应确保它不会干扰其他 scope 相关逻辑,或产生意外的授权提示。
参考实现
官方 MCP SDK 将提供展示本指导的参考实现:
- TypeScript SDK:客户端
offline_accessscope 处理 - Python SDK:客户端
offline_accessscope 处理 - 授权服务器示例:演示如何检查客户端能力
- 客户端一致性测试:便于验证 SDK 实现
SEP 被接受后将补充实现链接。
致谢
本提案通过 MCP Discord 的授权频道讨论形成,贡献者包括:
- Aaron Parecki(OAuth/OIDC 专业知识)
- Paul Carleton(MCP 授权指导)
- Simon Russell(OIDC 部署经验)