MCP 生产鉴权:客户端注册、JWKS 刷新、受众钉住的 token


文档摘要

MCP 生产鉴权:客户端注册、JWKS 刷新、受众钉住的 token 本节摘要:第 16 节把 OAuth 2.1 的状态机在内存里立了起来。到了 2026 年,你交付给真实组织的每个 MCP 服务端背后都得顶着生产级鉴权——能扩展到无限客户端群体的客户端注册(首选客户端 ID 元数据文档 CIMD,RFC 7591 动态注册作为向后兼容的回退)、授权服务端元数据发现(RFC 8414 或 OpenID Connect Discovery)、不会在凌晨三点让 token 校验崩掉的 JWKS 缓存刷新,以及拒绝跨资源重放的受众钉住 token。本节用三个角色——授权服务端、资源服务端(MCP 服务端)、客户端——把整张面建模出来,让你追踪从发现到一次受校验的工具调用之间的每一跳。

MCP 生产鉴权:客户端注册、JWKS 刷新、受众钉住的 token

本节摘要:第 16 节把 OAuth 2.1 的状态机在内存里立了起来。到了 2026 年,你交付给真实组织的每个 MCP 服务端背后都得顶着生产级鉴权——能扩展到无限客户端群体的客户端注册(首选客户端 ID 元数据文档 CIMD,RFC 7591 动态注册作为向后兼容的回退)、授权服务端元数据发现(RFC 8414 或 OpenID Connect Discovery)、不会在凌晨三点让 token 校验崩掉的 JWKS 缓存刷新,以及拒绝跨资源重放的受众钉住 token。本节用三个角色——授权服务端、资源服务端(MCP 服务端)、客户端——把整张面建模出来,让你追踪从发现到一次受校验的工具调用之间的每一跳。

规范说明(2025-11-25):2025 年 11 月的 MCP 授权规范把动态客户端注册(DCR)从 SHOULD 降级为 MAY,并把**客户端 ID 元数据文档(CIMD)**作为推荐的默认注册机制。本节按规范的优先级顺序讲这两者,代码走查里仍保留 DCR,因为它在一个进程里完全自洽。

学习目标

阅读完本节,你应当能够:

  1. 通过 RFC 8414 元数据发现授权服务端,并校验这份契约。
  2. 实现 RFC 7591 动态客户端注册,让 MCP 客户端无需管理员干预即可注册。
  3. 按计划缓存并刷新 JWKS,让签名校验扛过密钥轮换。
  4. 用 RFC 8707 资源指示符把 token 钉到单个 MCP 资源,拒绝 confused-deputy 复用。
  5. 把三个角色干净地分开——授权服务端、资源服务端、客户端——让各自只做自己该做的校验。
  6. 读一份 IdP 能力矩阵,在 IdP 满足不了 MCP 授权配置时拒绝部署。

一、问题与直觉

第 16 节的模拟器在内存里跑 OAuth 2.1。生产环境有三个模拟器看不到的运营缺口。

第一个缺口是注册。一个真实组织跑着几百个 MCP 服务端、几千个 MCP 客户端。运维不会把每个 Cursor 用户都手工注册成 OAuth 客户端。2025-11-25 规范给了客户端一条优先级顺序:有预注册 client_id 就用;否则用客户端 ID 元数据文档(CIMD)(客户端用一个自己控制的 HTTPS URL 作为 client_id,授权服务端去元数据);否则回退到 RFC 7591 动态客户端注册(DCR)(客户端推送一个 POST /register,当场拿回 client_id);否则提示用户。CIMD 是推荐默认,因为它完全去掉了逐服务端注册,同时保持以 DNS 为根的信任模型;DCR 为向后兼容保留。两者都从授权服务端的元数据发现自己的入口:client_id_metadata_document_supported(CIMD)、registration_endpoint(DCR)。

第二个缺口是密钥轮换。JWT 校验依赖授权服务端的签名密钥,以 JSON Web Key Set(JWKS)形式发布。授权服务端按计划轮换(通常每小时,事故响应下可能更快)。一个只在启动时拉一次 JWKS 的 MCP 服务端,在轮换窗口之前校验都正常,之后每个请求都失败,直到重启。生产里要把 JWKS 接成一个带刷新任务的缓存值,在旧密钥过期前覆盖缓存,并对缓存未命中的情况加一次回退拉取——因为可能来了一个用比缓存更新的密钥签的 token。

第三个缺口是受众绑定。第 16 节引入了 RFC 8707 资源指示符。在生产里,它变成每次请求都要做的硬声明校验。MCP 服务端把 token.aud 与自己的规范资源 URL 对比,不匹配就 HTTP 401。这是应对上游 MCP 服务端(或一个持着为某个服务端签发 token 的恶意客户端)把那张 token 重放给同一信任网格里另一个服务端的唯一防线。

本节把每个缺口映射到面上一块具体的东西:元数据文档是个 HTTP 端点;JWKS 缓存刷新是个定时任务加键值缓存;JWT 校验是资源服务端在派发任何工具前跑的一套例程。三个角色各司其职:授权服务端签发并轮换密钥,资源服务端缓存并校验,客户端发现并注册。

二、从零实现

RFC 8414 —— 授权服务端元数据

/.well-known/oauth-authorization-server 上的一份文档,描述客户端需要的一切:

{ "issuer": "https://auth.example.com", "authorization_endpoint": "https://auth.example.com/authorize", "token_endpoint": "https://auth.example.com/token", "jwks_uri": "https://auth.example.com/.well-known/jwks.json", "registration_endpoint": "https://auth.example.com/register", "response_types_supported": ["code"], "grant_types_supported": ["authorization_code", "refresh_token"], "code_challenge_methods_supported": ["S256"], "scopes_supported": ["mcp:tools.read", "mcp:tools.invoke"], "token_endpoint_auth_methods_supported": ["none", "private_key_jwt"] }

拿到一个 MCP 资源 URL 的客户端,会链式发现:先从 RFC 9728 的 oauth-protected-resource(资源服务端的文档)拿到 issuer,再从 oauth-authorization-server(本 RFC)拿到所有端点。客户端绝不硬编码授权 URL。

签下这份契约前,你要校验:

  • code_challenge_methods_supportedS256(RFC 7636 的 PKCE)。规范明确:若该字段缺失,授权服务端就不支持 PKCE,客户端必须拒绝继续。
  • grant_types_supportedauthorization_code,拒绝 passwordimplicit
  • 至少广告一条注册路径:client_id_metadata_document_supported: true(CIMD,优先) registration_endpoint(RFC 7591 DCR,回退)。任一即满足契约;你不再硬要求 DCR。
  • response_types_supported 对 OAuth 2.1 恰为 ["code"]

S256 缺失,MCP 服务端拒绝对该 IdP 部署——PKCE 无降级模式。若两条注册路径都没广告、你也没有预注册的 client_id,你也无法注册;错的不是代码,是部署清单。

RFC 9728(回顾)—— 受保护资源元数据

第 16 节讲过。生产里的增量:这份文档是客户端找到「这个 MCP 服务端信任的授权服务端」的唯一去处。单个 MCP 服务端可能接受来自多个 IdP 的 token(一个面向员工,一个面向合作伙伴)。RFC 9728 声明这组 IdP,RFC 8414 文档化每个 IdP 支持什么。

客户端 ID 元数据文档(CIMD,推荐默认)

CIMD 把注册从推送翻成拉取。客户端不请授权服务端铸造 client_id,而是用一个自己控制的 HTTPS URL 作为 client_id。该 URL 解析到一份 JSON 元数据文档;授权服务端在 OAuth 流程中按需去拉。信任根植于 DNS:如果服务端运营者信任 app.example.com,它就信任从 https://app.example.com/client.json 服务的客户端。没有注册往返、没有会耗尽的 client_id 命名空间、没有需要同步的逐服务端状态。

客户端托管的元数据文档:

{ "client_id": "https://app.example.com/oauth/client.json", "client_name": "Example MCP Client", "client_uri": "https://app.example.com", "redirect_uris": ["http://127.0.0.1:7333/callback", "http://localhost:7333/callback"], "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "token_endpoint_auth_method": "none" }

文档里的 client_id必须等于它被服务所在的 URL(授权服务端会校验;不匹配即拒)。授权服务端用 RFC 8414 元数据里的 client_id_metadata_document_supported: true 广告支持。

两个安全事实,规范说得很直白:

  • SSRF:授权服务端去拉一个攻击者提供的 URL,必须防服务器端请求伪造(不拉内网/管理端点)。
  • localhost 冒充:光靠 CIMD 挡不住本地攻击者声称合法客户端的元数据 URL 并绑定任意 localhost redirect。授权服务端必须在同意时清楚显示 redirect URI 主机名,应当对仅 localhost 的 redirect 发警告。

CIMD 无需服务端状态,不像 DCR 要立一个注册器。客户端侧只读:从一个静态 HTTPS 端点服务你的元数据文档,让授权服务端来拉。

RFC 7591 —— 动态客户端注册(回退/向后兼容)

DCR 现在是 MAY,为兼容 2025-11-25 之前的部署和尚未支持 CIMD 的 IdP 保留。没有它(也没有 CIMD 或预注册)时,每个 MCP 客户端(Cursor、Claude Desktop、自定义 Agent)都得跟 IdP 管理员做带外交换。有 DCR 时,客户端 POST:

POST /register Content-Type: application/json { "redirect_uris": ["http://127.0.0.1:7333/callback"], "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "token_endpoint_auth_method": "none", "scope": "mcp:tools.invoke", "client_name": "Cursor", "software_id": "com.cursor.cursor", "software_version": "0.42.0" }

服务端回 client_id 与一个用于后续更新的 registration_access_tokentoken_endpoint_auth_method: none 对跑在用户设备上的 MCP 客户端是正确默认——只拿 client_id,没有会外泄的 client_secret。PKCE 提供公共客户端需要的占有证明。

三个生产陷阱:

  • 注册端点必须按源 IP 限流,否则攻击者脚本数百万假注册,耗尽 client_id 命名空间。
  • 部分 IdP 要求 software_statement(一个为客户端背书的签名 JWT)。本节 mock 跳过;生产要加校验步骤,对除 localhost redirect 之外的未签名注册一律拒。
  • registration_access_token 必须以哈希存储,不能明文。它一旦泄露,攻击者就能改写客户端的 redirect URI。

RFC 8707(回顾)—— 资源指示符

第 16 节定了形状。生产规则:每次 token 请求都带 resource=<规范 MCP URL>,MCP 服务端每次调用都校验 token.aud 与自己的资源 URL 匹配。规范 URI 是该服务端最具体的标识:小写 scheme 与 host、无 fragment、按约定无尾斜杠。路径组件按规则剥离——需要时用来标识单个 MCP 服务端。https://mcp.example.comhttps://mcp.example.com/mcphttps://mcp.example.com:8443https://mcp.example.com/server/mcp 都是合法规范 URI。每个服务端选一个,把 aud 钉到它。

RFC 7636(回顾)—— PKCE

OAuth 2.1 里 PKCE 强制。本节的授权码流始终带 code_challengecode_verifier。服务端拒绝任何无 verifier 或 verifier 哈希不匹配存储 challenge 的 token 请求。

MCP 规范 2025-11-25 授权配置

MCP 规范(2025-11-25)对 MCP 服务端授权层该做什么写得很精确:

  • 实现 RFC 9728 受保护资源元数据,通过 401 上的 WWW-Authenticate: Bearer resource_metadata="..."知名 URI /.well-known/oauth-protected-resource 提供其位置(SEP-985 让头变成可选、有知名回退)。元数据的 authorization_servers 字段必须命名至少一个服务端。
  • 仅通过 Authorization: Bearer ... 接受 token,每次请求——绝不在查询串里,绝不仅在校验在会话开始时做一次。
  • 每次请求校验 audissexp 与所需 scope。服务端必须校验 token 是专门为它签发的(受众);缺失或不匹配的 aud 被拒,绝不作通配。
  • 401/403 时返回 WWW-Authenticate: Bearer,携带 error=...resource_metadata="<PRM-URL>" 参数(元数据文档的 URL,不是裸资源),以及 insufficient_scope(403)时带 scope="..."。注意:这个参数叫 resource_metadata,是一个发现指针——challenge 里没有 resource 参数。
  • 授权服务端发现接受 RFC 8414 OAuth 元数据 OpenID Connect Discovery 1.0;客户端必须按优先级顺序尝试两种知名后缀。
  • mix-up 攻击是客户端(不是服务端)的活:重定向前记录预期的 issuer,兑换 code 前校验授权响应的 iss 参数(RFC 9207)。光靠 PKCE 挡不住 mix-up,因为客户端会把它的 code_verifier 交给被引向的任何 token 端点。

OAuth 2.1 草案是基底;RFC 8414/7591/8707/9728/9207 + RFC 7636 + CIMD 是表面;MCP 规范是配置。

IdP 能力矩阵

并非每个 IdP 都支持完整 MCP 配置。下表是截至 2025-11-25 规范的事实陈述,是部署闸门,不是推荐。

IdP 类别 AS 元数据(8414/OIDC) CIMD RFC 7591 DCR RFC 8707 资源 RFC 7636 S256 PKCE 备注
自托管(Keycloak) 出现中 是(24.x 起) 本节 MCP 配置的参考 IdP;端到端 DCR 全通,CIMD 跟进新规范
企业 SSO(Microsoft Entra ID) 出现中 是(高端租户层) DCR 可用性因租户层而异;部署前在目标租户核实
企业 SSO(Okta) 出现中 是(Okta CIC / Auth0) DCR 在 Auth0(现 Okta CIC)可用;经典 Okta 组织需管理员预注册
社交登录 IdP(通用) 不定 罕见 罕见 多把客户端当静态伙伴;无自助注册。仅作身份源,在上层叠自己的 MCP 感知授权服务端
自研 不定 不定 不定 不定 不定 自研就做全配置,优先 CIMD。跳过 PKCE 或受众绑定会破坏 MCP 授权契约

部署清单的拒绝规则:选定的 IdP 不在 code_challenge_methods_supportedS256,MCP 服务端拒绝启动——PKCE 无降级模式。注册是更软的闸门:需要一条可用路径(预注册的 client_idclient_id_metadata_document_supported: trueregistration_endpoint)。光 DCR 缺失不再触发拒绝,因为 CIMD 或预注册可顶上。

JWKS 刷新模式(在 AS 轮换,在资源服务端刷新)

把两个动词分开,因为混它们是真生产 bug:

  • 轮换(Rotate)授权服务端做的:铸一把新签名密钥,发布进 JWKS,稍后退役旧的。资源服务端与此无关,也做不到——它不持 IdP 的私钥。
  • 刷新(Refresh)资源服务端做的:重新 GET 已发布的 JWKS 进缓存。这是资源服务端唯一能做的 JWKS 动作。

生产的失败模式是缓存变陈。用定时刷新任务加键值缓存解决。资源服务端跑一个任务(cron、定时器……),按固定间隔拉 <issuer>/.well-known/jwks.json 并覆盖 cache[issuer] = {keys, fetched_at}。校验器读这个缓存。kid 不在缓存里的 token 触发一次同步刷新作回退,然后重查。一次同时处理两种情况:计划刷新,以及一把全新密钥签的 token 在下次计划刷新前到达的重叠窗口。

回退必须是重新拉取,绝不能是轮换。如果你把缓存未命中路径接到「轮换并铸造」,两件事会坏:① 铸一把新密钥产出的 kid 仍不匹配 token,查找照样失败;② 攻击者用随机 kid 喷 token,逼出无界的密钥创建——自找的 DoS。重新拉取是幂等的,假 kid 最多浪费一次拉取。

缓存形状:

{ "https://auth.example.com": { "keys": [ {"kid": "k_2026_03", "kty": "RSA", "n": "...", "e": "AQAB", "alg": "RS256", "use": "sig"}, {"kid": "k_2026_04", "kty": "RSA", "n": "...", "e": "AQAB", "alg": "RS256", "use": "sig"} ], "fetched_at": 1772668800 } }

同时两把密钥是稳态。授权服务端先引入下一把(k_2026_04)再退役上一把(k_2026_03),旧密钥签的 token 在过期前仍有效。缓存持有并集,校验器按 kid 选。

校验例程

MCP 服务端在派发任何工具前跑校验。code/main.py 用的形状:

result = server.validate(bearer_token, required_scope="mcp:tools.invoke") if not result["valid"]: return {"status": result["status"], "WWW-Authenticate": result["www_authenticate"]}

validate 解码 JWT、从 JWKS 缓存(未命中时刷新一次)解析签名密钥、验签,然后依次查 iss(对照 allow-list)、aud(对照本服务端的规范资源)、exp、所需 scope——首次失败就返回一个 WWW-Authenticate challenge。把它放在资源服务端的单一例程里,意味着每个入口(每个工具调用、每种传输)都走同样校验;没有不先校验就到工具的路径。

受众重放走查(access-token 权限限制)

服务端 A(notes.example.com)与服务端 B(tasks.example.com)都注册到同一个授权服务端。服务端 A 被攻陷。攻击者拿用户的 notes token,重放给服务端 B。

服务端 B 的校验器:

  1. 解码 JWT,按 kid 拉 JWKS,验签。
  2. iss 是否在其受保护资源元数据的 authorization_servers 里。(通过——同一 IdP。)
  3. aud == "https://tasks.example.com"。(失败——token 的 audhttps://notes.example.com。)
  4. 返回 401,带 WWW-Authenticate: Bearer error="invalid_token", error_description="audience mismatch", resource_metadata="https://tasks.example.com/.well-known/oauth-protected-resource"

受众声明是协议层挡这攻击的唯一防线。为性能跳过它是最常见的生产错误;校验器必须每次请求都跑,而不是只在会话开始跑一次。规范称之为 access-token 权限限制:MCP 服务端 MUST 拒绝任何没在受众里命名它的 token。

命名注意:规范把 confused deputy 这个词留给一个相关但不同的问题——一个 MCP 服务端作为 OAuth 代理对接第三方 API,用静态 client ID,在未取得逐客户端用户同意时转发 token。受众绑定修的是上面的重放;confused-deputy 的修法是逐客户端同意加上绝不把入站 token 透传给上游 API(MCP 服务端 MUST 拿自己单独的上游 token)。

Mix-up 攻击(客户端侧防御,服务端给不了)

一个客户端一生会跟多个授权服务端打交道。恶意 AS 能让客户端把诚实 AS 的授权码,在攻击者的 token 端点兑换掉。受众绑定帮不上——攻击发生在任何 token 存在之前。防御在客户端(RFC 9207):

  1. 重定向前,客户端从校验过的 AS 元数据记录预期的 issuer
  2. 授权响应上,客户端把返回的 iss 参数与记录的 issuer 比对(简单字符串比对,无归一化),才把 code 发往任何地方。
  3. 不匹配(或 AS 广告了 authorization_response_iss_parameter_supported 却没带 iss)→ 拒,连 error 字段都不展示。

光 PKCE 挡不住 mix-up,因为客户端会把 code_verifier 交给被引向的任何 token 端点。这就是为何规范要把 issuer 跟 PKCE verifier 与 state 一起按请求记录。

失败模式

  • JWKS 变陈:AS 轮换一把密钥后,校验器拒掉合法 token。修法是上面 cron 刷新 + 缓存未命中重拉。绝不要不带刷新任务地缓存 JWKS。
  • 把轮换当回退:把缓存未命中路径接到轮换并铸造而非重拉是真 bug:它永远产不出缺失的 kid,还把攻击者可控的 kid 值变成密钥创建 DoS。回退必须是幂等的 refresh_jwks
  • aud 声明:部分 IdP 默认不写 aud,除非 token 请求带 resource。校验器必须拒绝缺 aud 的 token,不能把缺失当通配。
  • iss 校验导致 mix-up:不校验 RFC 9207 iss 的客户端,可能被引去把诚实 AS 的 code 兑到攻击者的 token 端点。这是客户端侧失败,资源服务端补不了。
  • scope 升级竞态:同一用户两个并发步进流可能都成功,产出两张 scope 不同的 access token。校验器必须用本次请求呈现的 token,而不是查「用户当前 scope」——那会开 TOCTOU 窗口。
  • 注册 token 失窃:泄露的 registration_access_token 让攻击者能改写 redirect URI。静态存哈希;要求客户端每次更新都呈明文;有嫌疑就轮换。
  • 未钉 iss:接受任意 iss 的校验器,让攻击者自起一个授权服务端、为目标受众注册客户端、签 token。受保护资源元数据的 authorization_servers 列表就是 allow-list,必须强制。

三、框架对比

能力 自建 stdlib Keycloak Auth0/Okta CIC Entra ID 社交 IdP
8414/OIDC 元数据 手实现 不定
CIMD 手实现 出现中 出现中 出现中
RFC 7591 DCR 手实现 高端层 罕见
RFC 8707 资源 手实现 是(24.x 起) 罕见
S256 PKCE 手实现

💡 心法:IdP 能力矩阵是部署闸门,不是采购推荐。先核实目标租户支持 S256 与至少一条注册路径(CIMD/预注册/DCR),再决定能否上生产。社交 IdP 只当身份源用,在上层叠一个你自己的、MCP 感知的授权服务端。

四、可复用产物

本节产出 outputs/skill-mcp-auth.md——给定一份 MCP 服务端配置和一份 IdP 能力集,这个 skill 产出要立起的授权面:受保护资源元数据、要用的注册路径(CIMD、预注册或 DCR 回退)、JWKS 刷新计划、scope 映射,以及 IdP 不支持完整 RFC 配置时要应用的拒绝规则。

code/main.py 用 stdlib Python 与三个角色——AuthorizationServerResourceServerClient——走完整生产流。流程:授权服务端在 /.well-known/oauth-authorization-server 发布 RFC 8414 元数据;客户端调元数据端点检查注册选项(CIMD 的 client_id_metadata_document_supported、DCR 的 registration_endpoint)与 S256 PKCE 支持;走查走 DCR 回退路径,客户端 POST /register(RFC 7591)拿回 client_id(CIMD 客户端则改为呈上自己的 HTTPS client_id URL 并跳过此步);客户端跑带 resource 指示符(RFC 8707)的 PKCE 授权码流(RFC 7636);用 Authorization: Bearer ... 调 MCP 服务端工具;服务端跑 validate,从 JWKS 缓存解析签名密钥;IdP 轮换一把密钥,定时 refresh_jwks 把 JWKS 重拉进缓存;下一次调用在重叠窗口里用刷新后的密钥校验,旧 token 仍有效;一次对另一 MCP 资源的受众重放尝试得 401,带 audience mismatchresource_metadata 指针。

本节 JWT 用 HS256 共享密钥(只为在 stdlib 上跑)。生产用 RS256 或 EdDSA 配上述 JWKS 模式,校验逻辑其余部分完全一致。因 IdP 与资源服务端同进程,refresh_jwks 直接读授权服务端的密钥列表;在网络上它是对 jwks_uri 的 HTTP GET

五、练习

  1. 追踪流:运行 code/main.py,留意步骤 6 里 IdP 轮换密钥、定时 refresh_jwks 重拉、旧 token(重叠窗口)与新 token 都无需重启地校验通过。

  2. 加 IdP:在受保护资源元数据的 authorization_servers 列表里加一个 IdP,签一张它签的 token,确认校验器接受;再签一张未列 IdP 签的 token,确认被拒并回 WWW-Authenticate: Bearer error="invalid_token", error_description="iss not allowed"

  3. 限流注册:给 register_client 加一个按源 IP 的令牌桶(用按 IP 的字典),在注册器接受请求前跑。

  4. 补字段校验:读 RFC 7591,找出本节 /register 处理器没校验的两个字段并补上(提示:software_statementredirect_uris 的 URI scheme)。

  5. 加 CIMD 路径:服务一个 client.json,其 client_id 等于自身 URL,让授权服务端拉取并校验(client_id ≠ URL 即拒)。确认 CIMD 客户端在不调 register_client 的情况下注册。

  6. 证明 DoS 修复:给校验器送一个带随机 kid 的 token,确认 refresh_jwks 至多跑一次、授权服务端的密钥数不增长。然后故意把回退重接到轮换并铸造,看密钥数随每个假 token 攀升——事后改回重拉。

  7. 实现 mix-up 防御:实现混搭小节的客户端侧 RFC 9207 iss 校验:授权请求前记录预期 issuer,授权响应的 iss 不匹配即拒。

本节要点回顾

  1. 三大生产缺口:注册(优先 CIMID,DCR 回退)、JWKS 轮换(定时刷新 + 未命中重拉)、受众绑定(每次请求查 token.aud)。
  2. CIMD 是推荐默认:用 HTTPS URL 作 client_id,授权服务端元数据,信任根植于 DNS,无逐服务端状态。
  3. DCR 降为 MAY:仅作兼容与回退,注册端点必须按 IP 限流,registration_access_token 要哈希存。
  4. 轮换 vs 刷新必须分清:轮换在 AS 铸/退役密钥;刷新在资源服务端重拉已发布 JWKS。回退必须是重拉,接轮换会自造 DoS。
  5. 每次请求校验 aud:这是协议层挡跨服务端 token 重放的唯一防线,规范称 access-token 权限限制,不能为性能省略。
  6. PKCE 无降级模式:IdP 不列 S256 即拒绝部署。
  7. confused-deputy 与受众重放是两件事:受众绑定修重放;confused-deputy 的修法是逐客户端同意加绝不透传入站 token 给上游 API。
  8. mix-up 是客户端侧防御:PKCE 挡不住;必须用 RFC 9207 iss 校验,授权请求前记录 issuer、响应不匹配即拒。

下一节,我们把视野从「Agent 调工具」扩展到「Agent 调 Agent」——A2A 协议:Agent Card、Task 生命周期、对内部推理保持不透明的协作。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U