跳到正文
MuoCeon 文档中心
第三方 OAuth 接入接入准备

发现元数据

从标准发现文档拿到端点、能力与 scope,不要硬编码路由表。

MuoCeon 授权服务器发布三份标准发现文档。接入时请优先读取它们,而不是把端点地址抄进代码——地址、算法、能力列表都可能演进,元数据会跟着一起变。

文档地址

假设 issuer 为 https://id.example.com/v1/oauth:

文档路径规范
授权服务器元数据https://id.example.com/.well-known/oauth-authorization-server/v1/oauthRFC 8414
OpenID Provider 元数据https://id.example.com/.well-known/openid-configuration/v1/oauthRFC 8414 路径形式
OpenID Provider 元数据(另一拼法)https://id.example.com/v1/oauth/.well-known/openid-configurationOIDC Discovery
受保护资源元数据(auth)https://id.example.com/.well-known/oauth-protected-resource/v1/authRFC 9728
受保护资源元数据(oauth)https://id.example.com/.well-known/oauth-protected-resource/v1/oauthRFC 9728
受保护资源元数据(account)https://id.example.com/.well-known/oauth-protected-resource/v1/accountRFC 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。

拿到元数据之后该做什么

  1. 校验 issuer 与预期一致(防止指向别的授权服务器)。
  2. 从 jwks_uri 拉公钥,用 kid 匹配后验证令牌签名,不要缓存超过 Cache-Control 声明的时长(当前是 5 分钟)。
  3. 用 token_endpoint、revocation_endpoint 等字段构造请求,不写死路径。
  4. 只申请 scopes_supported 里出现、且你登记时获批的 scope。

不要把 userinfo 挂到 oauth 路径下

UserInfo 在 https://id.example.com/v1/auth/userinfo(受众为 auth)。用 oauth 受众的令牌调它会被拒绝——受众不匹配是硬失败,不是降级。

本页目录