11.4 客户端凭证与身份断言扩展


文档摘要

11.4 客户端凭证与身份断言扩展 本节摘要:本节讲 OAuth 的两个特殊场景扩展。一是客户端凭证(Client Credentials)——机器到机器的认证,无用户参与,适用于服务间调用、定时任务、后台编排。二是身份断言(Identity Assertion)——把一个已有的外部身份(如公司 SSO、第三方登录)带进 MCP,避免用户重复登录。两者都解决了「标准授权码流需要用户参与」的局限。读完本节,你能在无用户场景与外部 IdP 场景下正确接入 MCP。 一、标准授权码流的局限 第 11.3 节的授权码流,有个隐含前提——有用户在浏览器里操作。但有两类场景没有用户: 这两个场景,授权码流都搞不定。SDK 提供两个扩展解决——客户端凭证(场景一)与身份断言(场景二)。

11.4 客户端凭证与身份断言扩展

本节摘要:本节讲 OAuth 的两个特殊场景扩展。一是客户端凭证(Client Credentials)——机器到机器的认证,无用户参与,适用于服务间调用、定时任务、后台编排。二是身份断言(Identity Assertion)——把一个已有的外部身份(如公司 SSO、第三方登录)带进 MCP,避免用户重复登录。两者都解决了「标准授权码流需要用户参与」的局限。读完本节,你能在无用户场景与外部 IdP 场景下正确接入 MCP。

一、标准授权码流的局限

第 11.3 节的授权码流,有个隐含前提——有用户在浏览器里操作。但有两类场景没有用户:

场景一:机器到机器 服务 A → 调用 → MCP 服务 B → 没有用户浏览器,授权码流跑不起来 场景二:已有外部身份 用户已在公司 SSO 登录 → 不想在 MCP 里再登录一次 → 但 MCP 不知道用户的 SSO 身份

这两个场景,授权码流都搞不定。SDK 提供两个扩展解决——客户端凭证(场景一)与身份断言(场景二)。

二、客户端凭证扩展:机器到机器

客户端凭证(Client Credentials) 是 OAuth 的一种授权方式,不需要用户参与——客户端用自己的凭证直接换令牌:

标准授权码流(需要用户): 客户端 → 用户同意 → 授权码 → 令牌 (用户是关键) 客户端凭证流(无用户): 客户端(用自己的 ID+密钥)→ 直接换令牌 (无用户参与)

适用场景:

场景 例子
服务间调用 后端服务 A 调 MCP 服务 B
定时任务 后台脚本定期同步数据
自动化编排 CI/CD 流水线调 MCP 工具
无头客户端 无 UI 的命令行工具

三、客户端凭证的客户端实现

SDK 提供客户端凭证扩展,客户端用 client_credentials 流获取令牌:

from mcp.client.auth.extensions import ClientCredentialsProvider # 配置客户端凭证 provider = ClientCredentialsProvider( token_url="https://mcp.example.com/token", client_id="my_service", # 服务注册的 client_id client_secret="...", # 服务密钥 scopes=["tools:read", "tools:call"], # 需要的权限 ) async with Client( "http://mcp.example.com/mcp", auth=provider, ) as client: # SDK 用 client_credentials 流获取令牌(无用户) result = await client.call_tool("get_data", {...})

客户端凭证流的关键:

  • 无浏览器跳转(没用户)
  • 用 client_id + client_secret 直接换令牌
  • 令牌通常短命(因为无法 refresh,过期重新换)

💡 技巧:客户端凭证适合「服务身份」而非「用户身份」。客户端凭证拿到的令牌,代表的是「调用方服务」(如 my_service),不是某个用户。所以服务端的权限控制要基于「服务身份」,而非用户身份。如果你的逻辑需要「是哪个用户」,客户端凭证不合适,要用标准授权码流或身份断言。

四、服务端配置客户端凭证

服务端要支持客户端凭证,需要:

  • 允许客户端用 client_credentials 授权类型注册
  • 在令牌签发时,识别「服务身份」

这部分在服务端的存储实现里配置(回顾第 11.2 节的存储接口)。支持客户端凭证的服务端,会在 /token 端点接受 grant_type=client_credentials 的请求。

五、身份断言扩展:把外部身份带进来

身份断言(Identity Assertion) 解决「已有外部身份,不想重复登录」的场景。它让你把一个已有的身份(如 SSO、第三方登录)断言给 MCP,换得一个 MCP 令牌:

场景:用户已在公司 SSO 登录 用户 → 公司 SSO 登录 → 拿到 SSO 令牌 │ ▼ 想用 MCP 服务,不想再登录 客户端把 SSO 令牌作为「身份断言」给 MCP │ ▼ MCP 验证断言 MCP 信任 SSO,接受断言 → 签发 MCP 令牌 │ ▼ 后续用 MCP 令牌访问

这种机制让 MCP 复用已有身份系统,而非自己重新认证。

六、身份断言的客户端实现

SDK 的身份断言扩展,让客户端把外部令牌带进来:

from mcp.client.auth.extensions import IdentityAssertionProvider # 已有的外部令牌(如 SSO 令牌) external_token = get_sso_token() # 从你的 SSO 系统拿 provider = IdentityAssertionProvider( external_token=external_token, # 外部身份令牌 token_url="https://mcp.example.com/token", # 其他配置 ) async with Client( "http://mcp.example.com/mcp", auth=provider, ) as client: # SDK 把外部令牌断言给 MCP,换 MCP 令牌 result = await client.call_tool(...)

身份断言流的关键:

  • 客户端已有外部令牌(来自 SSO、第三方登录等)
  • 把外部令牌「断言」给 MCP
  • MCP 配置信任该外部 IdP,接受断言签发 MCP 令牌

七、服务端配置身份断言

服务端要支持身份断言,需要配置「信任哪些外部 IdP」:

# 服务端配置信任外部 IdP(概念性) mcp = MCPServer( "Protected", auth=AuthSettings( provider=my_provider, trusted_issuers=["sso.company.com"], # 信任的 IdP # 其他配置 ) )

配置后,服务端会:

  • 验证身份断言的签名(确认来自可信 IdP)
  • 从断言提取用户身份
  • 签发 MCP 令牌

⚠️ 注意:身份断言的核心是「信任」。服务端必须严格验证断言——签名是否来自可信 IdP、是否过期、是否被篡改。接受未经验证的断言=允许任何人伪造身份。实现身份断言时,务必遵循 OIDC/OAuth 的安全最佳实践。

八、三种认证方式的对照

把三种认证方式放一起,帮你选对:

方式 谁参与 适合 例子
授权码流(11.3) 用户 + 客户端 有用户的交互应用 桌面应用、Web 应用
客户端凭证(本节) 仅客户端(服务身份) 机器到机器 服务间调用、定时任务
身份断言(本节) 客户端 + 外部 IdP 已有 SSO 的企业 公司内部 MCP 复用 SSO

判断口诀:

问:有用户在浏览器里操作吗? 有 → 授权码流 无 → 继续问 问:调用方是服务(机器),还是有外部身份要复用? 服务 → 客户端凭证 外部身份 → 身份断言

本节要点回顾

  1. 客户端凭证:机器到机器认证,无用户参与,客户端用 ID+密钥直接换令牌。
  2. 适用:服务间调用、定时任务、自动化编排、无头客户端。
  3. 客户端凭证代表服务身份,非用户身份,权限控制要相应设计。
  4. 身份断言:把已有外部身份(SSO、第三方登录)断言给 MCP,换 MCP 令牌。
  5. 身份断言让 MCP 复用已有身份系统,避免重复登录。
  6. 服务端要配置信任外部 IdP,严格验证断言签名。
  7. 三种方式选型:有用户→授权码流;服务→客户端凭证;外部身份→身份断言。

第 11 章结束。你已经掌握 OAuth 全链路:角色、服务端授权服务器、客户端 OAuth、客户端凭证、身份断言。第 12 章讲进阶——低层 API、扩展、中间件、可观测性。


发布者: 作者: 灏天文库 转发
评论区 (0)
U