第三方 OAuth 接入接入准备
发现元数据
从标准发现文档拿到端点、能力与 scope,不要硬编码路由表。
MuoCeon 授权服务器发布三份标准发现文档。接入时请优先读取它们,而不是把端点地址抄进代码——地址、算法、能力列表都可能演进,元数据会跟着一起变。
文档地址
假设 issuer 为 https://id.example.com/v1/oauth:
| 文档 | 路径 | 规范 |
|---|---|---|
| 授权服务器元数据 | https://id.example.com/.well-known/oauth-authorization-server/v1/oauth | RFC 8414 |
| OpenID Provider 元数据 | https://id.example.com/.well-known/openid-configuration/v1/oauth | RFC 8414 路径形式 |
| OpenID Provider 元数据(另一拼法) | https://id.example.com/v1/oauth/.well-known/openid-configuration | OIDC Discovery |
| 受保护资源元数据(auth) | https://id.example.com/.well-known/oauth-protected-resource/v1/auth | RFC 9728 |
| 受保护资源元数据(oauth) | https://id.example.com/.well-known/oauth-protected-resource/v1/oauth | RFC 9728 |
| 受保护资源元数据(account) | https://id.example.com/.well-known/oauth-protected-resource/v1/account | RFC 9728 |
well-known 前缀后必须补上 issuer 的路径段
因为 issuer 自带 /v1/oauth 这一段,按 RFC 8414 的规定,well-known 地址必须拼成
/.well-known/oauth-authorization-server/v1/oauth,而不是裸的 /.well-known/oauth-authorization-server。
OIDC 的两种拼法都被注册了,因为真实客户端会各试一种。
你会从元数据里读到什么
授权服务器元数据(节选):
{
"issuer": "https://id.example.com/v1/oauth",
"authorization_endpoint": "https://id.example.com/authorize",
"token_endpoint": "https://id.example.com/v1/oauth/token",
"revocation_endpoint": "https://id.example.com/v1/oauth/revoke",
"introspection_endpoint": "https://id.example.com/v1/oauth/introspect",
"jwks_uri": "https://id.example.com/v1/oauth/jwks",
"response_types_supported": ["code"],
"response_modes_supported": ["query"],
"grant_types_supported": ["authorization_code", "refresh_token", "client_credentials"],
"code_challenge_methods_supported": ["S256"],
"token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"],
"authorization_response_iss_parameter_supported": true,
"authorization_details_types_supported": [
"muoceon_credential_management",
"muoceon_session_management",
"muoceon_grant_management"
]
}关键点:
response_types_supported只有code——隐式流程不存在。code_challenge_methods_supported只有S256——plain不可用。authorization_response_iss_parameter_supported为true,意味着授权响应成功和拒绝都带回iss,客户端必须校验(见 授权码流程)。authorization_endpoint指向的是同意页,不是服务器上的/v1/oauth/authorize。后者只接受 POST + JSON,是给同意页提交决策用的内部接口。
受保护资源元数据
每个资源受众(auth / oauth / account)各有一份,声明「这个资源接受什么 scope、由哪个授权服务器签发」:
{
"resource": "https://id.example.com/v1/auth",
"authorization_servers": ["https://id.example.com/v1/oauth"],
"bearer_methods_supported": ["header"],
"scopes_supported": ["openid", "profile", "email", "offline_access", "auth:credentials:read", "..."],
}resource 的值与访问令牌里的 aud 数组中的完整 URI 一一对应。第三方应用通常只需要 auth 这一份——它对应身份类 scope。
拿到元数据之后该做什么
- 校验
issuer与预期一致(防止指向别的授权服务器)。 - 从
jwks_uri拉公钥,用kid匹配后验证令牌签名,不要缓存超过Cache-Control声明的时长(当前是 5 分钟)。 - 用
token_endpoint、revocation_endpoint等字段构造请求,不写死路径。 - 只申请
scopes_supported里出现、且你登记时获批的 scope。
不要把 userinfo 挂到 oauth 路径下
UserInfo 在 https://id.example.com/v1/auth/userinfo(受众为 auth)。用 oauth 受众的令牌调它会被拒绝——受众不匹配是硬失败,不是降级。