同一个服务端应用、部署、租户或安装实例复用一个 OAuth
client_id。每位用户分别完成 OAuth 授权,服务端为该用户单独保存 Token。不要为每次请求或每个用户注册新的 Client。先选方案和环境
本文使用 UAT 沙盒和 Production 环境。两套环境的 MCP resource、OAuth
resource、Token audience 和元数据地址必须一一对应,不能混用。MCP 配置只填地址,不要填 Access Token、Refresh Token 或 API Key。
先声明两个环境的 base_url,后面的地址都只在其后拼接路径:
环境地址
OAuth Endpoint
下面的路径在两个环境相同,只需和所选环境的base_url 拼接。授权地址和 Token 地址在可用时应以 Authorization Server Metadata 的返回值为准。
注册和授权的频率
服务端集成
一次性准备 OAuth Client
无论用哪种方案,Client 注册的 Scope 都是之后每次授权请求的上限。申请超出这个范围的 Scope 会返回invalid_scope,后续补充权限时也一样。所以注册时要写全 Agent 可能用到的 Scope。Clink MCP 使用下面这些 Scope,offline_access 用于签发 Refresh Token:
CIMD
CIMD 适合能维护公开 HTTPS 元数据的服务端 Agent。在自己的 HTTPS 域名下托管公开 JSON 文件,并把文件 URL 作为client_id:
- URL 使用 HTTPS,带路径,不带 query 和 fragment。
- 文件中的
client_id与文件 URL 完全一致。 - 直接返回 HTTP 200,
Content-Type为application/json;Clink 不会跟随跳转。 - 文件不超过 5 KB。
Pre-registration
Pre-registration 适合固定企业或合作方。接入前把client_name、固定 HTTPS redirect_uri、当前环境的 resource 和 Agent 可能用到的全部 Scope 提供给 Clink,由 Clink 完成配置并返回固定的 client_id。服务端不调用注册接口,也不需要托管 CIMD 文件;把这个 client_id 放在服务端配置中。
当前 Clink 的预注册 MCP Client 使用 public client,不需要 Client Secret,但仍必须使用 Authorization Code + PKCE(S256)。用户点击“连接 Clink”时,授权请求里的 client_id 使用这个固定值,每位用户的 Token 仍要单独保存。
DCR
DCR 适合需要动态 Client ID、按租户或实例隔离 Client,或目标 Authorization Server 只支持动态注册的场景。先读取 Authorization Server Metadata;只有返回registration_endpoint 时才调用注册。服务端应在部署、租户开通或首次安装时注册一次,保存返回的 client_id,后续所有用户复用它。
client_id 要持久化保存。它只代表 Client 注册成功,后续每位用户仍要单独登录和授权。当前 Clink 示例使用 public client(token_endpoint_auth_method=none),不需要 Client Secret。
Clink 不支持修改已注册的 Client。需要调整 redirect URI 或 Scope 时,要重新注册一个 Client,用户也要用新的 client_id 重新授权。
三种方案的区别在于 client_id 怎么取得,以及 redirect URI 和 Scope 在哪里登记。取得 client_id 后,用户授权、回调换 Token、调用 MCP、刷新 Token 的流程都按下面步骤执行。
用户点击“连接 Clink”时
1
读取 Protected Resource Metadata
请求当前环境的 Protected Resource Metadata,从
authorization_servers 取得 issuer。UAT 地址是 ${UAT_BASE_URL}/.well-known/oauth-protected-resource/mcp。2
读取 Authorization Server Metadata
请求
{issuer}/.well-known/oauth-authorization-server,读取 authorization_endpoint 和 token_endpoint。不要把端点写死在代码里。3
生成 state 和 PKCE 参数
服务端为当前用户生成随机
state 和 PKCE code_verifier,临时保存它们与内部用户 ID 的绑定,用 S256 计算 code_challenge。4
重定向到授权地址
将下面参数全部 URL 编码后带上。CIMD 使用公开 JSON 文件 URL;Pre-registration 使用 Clink 提供的固定 Client ID;DCR 使用注册接口返回并持久化的 Client ID。
scope 按当前需要申请,且不能超出 Client 注册的 Scope。MCP Server 首次返回的 401 会要求 wallet:read events:read events:consume;提前申请这两个 events Scope,可以避免 Operation 进行中再弹一次授权。需要 Refresh Token 时要包含 offline_access。UAT 和 Production 必须使用各自对应的 resource。
回调换 Token
用户完成登录和授权后,回调会收到code、state 和 iss;授权失败时会收到错误参数。如果 state 与保存的值不一致,或 iss 缺失、与 Authorization Server Metadata 中的 issuer 不一致,直接拒绝这次回调。
然后向 token_endpoint 发送 POST 请求,Content-Type 为 application/x-www-form-urlencoded。使用同一个回调地址和保存的 PKCE verifier,每个参数值都要 URL 编码:
client_secret 或 device_id。按内部用户 ID、环境和 client_id 加密保存 access_token、refresh_token、过期时间和 Scope。授权码只能兑换一次。
用 Token 调 MCP
后端用当前用户的 Access Token 请求对应环境的/mcp。Clink MCP 支持 2026-07-28 和 2025-06-18 两个协议版本。建议使用官方 MCP Client SDK:它会协商版本、发送必需的请求头并解析流式响应。让 SDK 指向 MCP 地址,并在运行时为当前用户带上 Authorization: Bearer 请求头。
如果直接发送 HTTP 请求,请使用 2025-06-18 流程。2026-07-28 没有 initialize 握手,并且每个请求都要附带协议元数据,建议交给 SDK 处理。
- 发送
initialize,protocolVersion设为2025-06-18。 - 发送
notifications/initialized。 - 调用
tools/list获取工具。 - 调用
tools/call执行业务。
Accept 请求头,否则服务端返回 406。响应可能是 text/event-stream 流,其中每个 data: 行是一条 JSON-RPC 消息。initialize 之后的每个请求,都要在 MCP-Protocol-Version 请求头里带上协商出的版本:
处理需要用户打开的链接
部分工具结果会带next_action,其 type 为 REDIRECT_USER,例如绑卡、完成 3DS 或为 Agent Pay 注册卡片。通过你自己的渠道把 params.redirect_url 发给用户。params.actor 为 USER_DEVICE_ONLY 时,必须由用户在自己的设备上打开,不要在 Agent 控制的浏览器里打开。用户从页面返回不代表这一步已经成功,要调用 get_operation 读取结果。
刷新和恢复
Access Token 过期时,向同一个token_endpoint 提交 grant_type=refresh_token、原 client_id、当前 Refresh Token 和同一个 resource。
每次刷新都会返回新的 Refresh Token,旧的随即失效。先保存新的 Refresh Token,再使用新的 Access Token。如果再次提交已失效的 Refresh Token,Clink 会判定为重复使用,并撤销这次授权下的全部 Refresh Token,用户必须重新授权。刷新操作要按用户、环境和 client_id 串行,多实例部署时也要保证。
- 遇到
401时刷新 Token;刷新失败则让用户重新授权。 - 遇到
403且错误为insufficient_scope时,从WWW-Authenticate响应头的scope参数读取所需 Scope,与已授予的 Scope 合并后让用户重新授权。合并后的 Scope 不能超出 Client 注册的 Scope。 - 支付、退款或指令超时时调用
get_operation查询,不能直接重复执行。
上线检查
- Client 注册只在初始化、部署、租户开通或首次安装时执行。
- Client 注册时写全 Agent 可能用到的 Scope,授权时只申请当前需要的 Scope。
- 每个用户的 Token、会话和 Operation 隔离保存。
- 回调地址与 Client 配置逐字符一致。
- Token、Client Secret 不放进配置、CIMD 文件或日志。
- UAT 和 Production 地址不混用。
- Refresh Token 按用户、环境和
client_id串行使用。 -
REDIRECT_USER链接发给用户打开,不要在 Agent 控制的浏览器里打开。