- 状态(Status): Final
- 类型(Type): Standards Track
- 创建(Created): 2026-02-04
- 作者(Author(s)): Wils Dawson (@wdawson)
- 担保人(Sponsor): Paul Carleton (@pcarleton)
- PR: #2207
摘要
本提案为 MCP 实现提供关于刷新令牌签发和请求的指南,尤其是在授权服务器支持offline_access 作用域时。offline_access 作用域源自 OIDC,但任何 OAuth 2.1 授权服务器都可以采用它,作为让客户端显式请求刷新令牌的机制。本 SEP 澄清了授权服务器和 MCP 客户端在使用此模式时的预期行为。
动机
MCP 的授权机制基于 OAuth 2.1,但许多现实部署使用的授权服务器同时也实现了 OpenID Connect(OIDC)。纯 OAuth 与 OIDC 之间的一个关键差异在于刷新令牌的处理方式:- 在纯 OAuth 2.1 中,没有标准机制让客户端显式请求刷新令牌。授权服务器基于客户端的能力(例如客户端元数据中的
refresh_token许可类型)及其自身策略决定是否签发。 - 在 OIDC(以及采用此约定的授权服务器)中,除 OAuth 逻辑之外,还存在
offline_access作用域,允许客户端显式请求刷新令牌。
-
客户端未请求刷新令牌:主要的 MCP 客户端(Cursor、Claude、VS Code 等)没有通过
offline_access作用域显式请求刷新令牌,因为它们不知道授权服务器是否支持、期望或要求它。 -
资源服务器不应指定
offline_access:offline_access作用域不是资源特定的作用域——它是客户端与授权服务器之间的关切。将其包含在WWW-Authenticate头部的scope参数或受保护资源元数据的scopes_supported中,在语义上是错误的,因为这暗示资源要求刷新令牌,而资源绝不会如此。 -
授权服务器可能不一致:在处理授权码许可时,不同的授权服务器在向不同客户端签发刷新令牌时可能有不同行为,尤其是当客户端未将
refresh_token指定为许可类型或未请求offline_access作用域时。 - 互操作性缺口:没有本指南,各实现可能行为不一致,导致糟糕的用户体验(频繁重新认证)或安全问题(向无法安全存储刷新令牌的客户端签发刷新令牌)。
规范
MCP 客户端要求
打算使用刷新令牌且有能力安全存储它们的 MCP 客户端**应当(SHOULD)**遵循以下指南:-
公告能力:客户端**应当(SHOULD)**在其
grant_types客户端元数据中包含refresh_token,以表明它们支持刷新令牌。 -
作用域增补:当客户端希望获得刷新令牌且授权服务器元数据在其
scopes_supported字段中包含offline_access时,客户端**可以(MAY)**在向授权服务器发起授权请求之前,将offline_access作用域添加到来自资源服务器的作用域列表中。 -
无保证:客户端**不得(MUST NOT)**假定公告支持或请求
offline_access就能保证收到刷新令牌。授权服务器基于其策略保留自由裁量权。
MCP 服务器(资源服务器)要求
MCP 服务器(作为 OAuth 2.0 受保护资源):-
**不应当(SHOULD NOT)**在
WWW-Authenticate头部的scope参数中包含offline_access,因为刷新令牌不是资源要求。 -
**不应当(SHOULD NOT)**在受保护资源元数据的
scopes_supported中包含offline_access,因为它不是资源特定的作用域。
理由
为何不在 401 响应中要求 offline_access?
offline_access 作用域与资源特定的作用域有本质不同。它代表客户端对长期访问的意愿,而非资源的要求。依据 OAuth 2.1 第 5.3.1 节,WWW-Authenticate 中的 scope 属性表示”访问所请求资源所需的访问令牌作用域”。由于资源不要求 offline_access,将其包含进去在语义上是错误的。
为何检查客户端元数据中的许可类型?为何不总是签发刷新令牌?
OAuth 2.1 要求客户端注册其所支持的许可类型。不支持refresh_token 许可的客户端要么:
- 无法安全存储刷新令牌
- 没有使用它们的机制
为何允许 offline_access 作为替代信号?
一些授权服务器——无论是完全符合 OIDC 还是仅采用此约定——只在显式请求 offline_access 时才签发刷新令牌。支持此模式为此类部署提供了一条兼容路径。客户端可以通过检查授权服务器元数据的 scopes_supported 中是否有 offline_access,来检测支持此约定的授权服务器,并相应地调整其行为。
所考虑的替代方案
-
在资源响应中强制
offline_access:被否决,因为它歪曲了资源的要求并造成反模式。 - 总是签发刷新令牌:被否决,因为它忽视了客户端能力和授权服务器的安全策略。
- 单独的 OIDC 专用规范:被否决,转而采用一种对纯 OAuth 和 OIDC 部署都适用的统一方式。
- 为授权服务器提供指南:被否决,转而依赖 OAuth 和 OIDC 规范来提供这一指南,因为它可能各有不同。
向后兼容性
本提案完全向后兼容:- 已经请求
offline_access的客户端继续有效 - 已经检查客户端能力的授权服务器继续有效
- MCP 服务器无需作任何更改
- 该指南是增量的,不改变既有的必需行为
安全影响
正面安全影响
- 降低令牌泄露风险:通过不向未公告支持的客户端签发刷新令牌,我们降低了长期令牌被不安全存储的风险。
- 纵深防御:基于风险的评估步骤给予授权服务器实施额外安全控制的灵活性。
考量
-
客户端元数据可能不够:由于客户端元数据是自我申报的,恶意行为者可能注册一个声称支持
refresh_token许可的客户端以获取长期令牌。授权服务器在决定是否签发刷新令牌时,**可以(MAY)**使用基于风险的评估步骤(见规范)来施加额外限制——例如域名允许列表、信誉检查或验证要求——而非仅仅依赖客户端元数据的声明。 -
作用域注入:添加
offline_access的客户端应确保这不干扰其他与作用域相关的逻辑,或造成意外的授权提示。
参考实现
演示本指南的参考实现将在官方 MCP SDK 中提供:- TypeScript SDK:客户端侧的
offline_access作用域处理 - Python SDK:客户端侧的
offline_access作用域处理 - 授权服务器示例:客户端能力检查的演示
- 客户端合规测试:便于对 SDK 实现进行验证
致谢
本提案通过 MCP Discord 授权频道的讨论发展而来,得到以下人士的意见:- Aaron Parecki(OAuth/OIDC 专业知识)
- Paul Carleton(MCP 授权指南)
- Simon Russell(OIDC 部署经验)