OIDC 流程
如果应用已经支持 OpenID Connect,或者你希望直接使用现有 OIDC 库,可以将 Sudomimus 作为标准 OIDC 提供方接入。Sudomimus 的 OIDC provider 部署在 oidc.sudomimus.com,支持带 PKCE 的授权码流程。你的应用在该流程中是接入方(Relying Party,RP)。
适用场景:
- 你的框架或平台原生支持 OIDC(Next-Auth、Spring Security、Keycloak adapter 等),希望直接把 Sudomimus 接入做 IdP。
- 你要和某个已经只接 OIDC 的伙伴系统对接。
- 你更熟悉 OIDC 的 client、scope 和 ID token 概念,不希望使用 Connect 协议。
如果你从零开始、只想做最小的自定义集成,Connect 协议 通常更短。
官方 SDK 主要覆盖 Connect、Session、Device、Native 与 token 验证辅助。如果你的 OIDC 应用还需要验证 Sudomimus 应用 access token,或使用 Session 的 introspect 和 logout,请参考 SDK。OIDC refresh token 必须通过提供方的 /token 端点刷新。
OpenID 认证
Section titled “OpenID 认证”OpenID Foundation 的提供方认证档案列出了 Sudomimus 的下列档案。每个档案检验提供方的一类行为。当前部署实际声明的能力,请以下方的 Discovery 文档为准。
| 档案 | 检验内容 |
|---|---|
| Basic OP | 使用授权码流程登录。 |
| Config OP | 通过 Discovery 发布提供方端点和能力。 |
| Implicit OP | 通过前端通道返回 ID Token,可同时返回访问令牌。 |
| Hybrid OP | 组合授权码与前端通道令牌。 |
| Dynamic OP | 动态客户端注册及相关配置。 |
| Form Post OP | 通过 HTTP 表单 POST 返回授权响应。测试覆盖 Basic、Implicit 和 Hybrid 流程。 |
| 3rd Party-Init OP | 提供方经接入方已注册的登录入口发起登录。 |
Discovery
Section titled “Discovery”Sudomimus 发布标准 OIDC discovery 文档。将库的 issuer 设置为 https://oidc.sudomimus.com 后,客户端库可以自动读取其余配置:
curl https://oidc.sudomimus.com/.well-known/openid-configurationSudomimus 不另外发布 OIDC OpenAPI schema。请通过 discovery 获取当前部署的 端点 URL 与已声明能力,通过 OpenID Connect 和 OAuth 标准理解协议语义,并以 本指南确认 Sudomimus 支持的 profile 与平台约束。生成的 OpenAPI 参考用于 Connect、Session、Native 和 Device 产品 API。
discovery 文档声明:
response_types_supported:["code", "id_token", "id_token token", "code id_token", "code token", "code id_token token"]。response_modes_supported:["query", "fragment", "form_post"]。Code 默认使用 query;其他模式须显式请求,使用前请核对已部署的 discovery。userinfo_signing_alg_values_supported:["RS256"];由客户端注册配置启用。authorization_response_iss_parameter_supported:true—— 授权回调按照 RFC 9207 标识提供方。grant_types_supported:["authorization_code", "implicit", "refresh_token"]。scopes_supported:["openid", "email", "profile", "offline_access"]。claims_supported包含sub、email、email_verified、name、given_name、family_name、picture和picture_animated。claim_state_endpoint指向 Sudomimus 提供方专属的实时 claim 策略与同意状态端点。id_token_signing_alg_values_supported:["RS256"]。code_challenge_methods_supported:["S256"]—— 包含授权码的流程中,公开客户端必须使用 PKCE,机密客户端推荐使用;不支持 plain。token_endpoint_auth_methods_supported:["private_key_jwt", "client_secret_basic", "client_secret_post", "none"]。ui_locales_supported:["en-US", "zh-CN"]。
在 with.sudomimus.com 中,为需要启用 OIDC 的应用完成以下配置:
-
添加一条 Layer 3 OIDC 返回规则:
{"returnMethod": "OIDC","payload": {"redirectUris": ["https://app.example.com/oidc/callback"],"postLogoutRedirectUris": ["https://app.example.com/"],"allowedResponseTypes": ["code"],"allowedGrantTypes": ["authorization_code", "refresh_token"],"applicationType": "web","allowedScopes": ["openid", "email", "profile", "offline_access"],"tokenEndpointAuthMethod": "private_key_jwt"}} -
与其他应用一样配置 Layer 1 和 Layer 2:至少添加一条认证规则(例如
PASSKEY_USERNAMELESS或PASSKEY_REASONED)和一条身份准入规则(例如允许特定邮箱的EMAIL规则)。OIDC 流程仍使用平台的同一套用户认证挑战。 -
选择客户端认证方式:
private_key_jwt(推荐用于机密客户端)—— RP 持有私钥,在/token上用 JWT assertion 做客户端认证。在应用的 OIDC 页面选择平台提供的 client-auth 密钥,或已注册的 RP 公钥(内联 JWKS 或 HTTPS JWKS URI)。使用对应私钥签名。验证只使用所选密钥来源。client_secret_basic(机密客户端)—— RP 在/token的 HTTPAuthorization: Basic头中携带共享密钥。client_secret_post(机密客户端)—— RP 在/token的表单体中发送共享密钥(client_id+client_secret参数)。none—— 仅限公开客户端(SPA、无后端的移动应用)。包含授权码的流程必须使用 PKCE S256。
client_secret_basic 和 client_secret_post 共用同一把应用密钥。请在 With 门户的应用页面生成或轮换它,并妥善保存。
应用的 applicationAnchor 就是你的 client_id。
开始登录前,请配置所选流程需要的规则和凭据,再由组织 OWNER 激活应用。新应用会保持 DRAFT,直到明确执行激活;登录要求应用为 ACTIVE,且所属组织和扇区均可用。
OIDC 流程
Section titled “OIDC 流程”sequenceDiagram
autonumber
participant RP as OIDC 接入方
participant Browser as 用户浏览器
participant OIDC as OIDC 提供方
participant Via as via.sudomimus.com
RP-->>Browser: 跳转到 /authorize<br/>state + nonce + PKCE challenge
Browser->>OIDC: GET /authorize
OIDC-->>Browser: 进入托管认证
Browser->>Via: 完成认证并确认授权
Via-->>Browser: 返回已注册的 redirect URI<br/>code + state + iss
Browser-->>RP: 授权回调
RP->>OIDC: POST /token<br/>code + PKCE verifier + 客户端认证
OIDC-->>RP: ID token + access token<br/>可选 refresh token
RP->>OIDC: GET 或 POST /userinfo<br/>Bearer access token
OIDC-->>RP: 经 scope 与授权筛选的声明
1. 授权请求
Section titled “1. 授权请求”把用户浏览器跳转到 /authorize,附带标准 OIDC 参数:
https://oidc.sudomimus.com/authorize ?client_id=my-app &redirect_uri=https%3A%2F%2Fapp.example.com%2Foidc%2Fcallback &response_type=code &scope=openid%20email%20profile &ui_locales=zh-CN%20en-US &state=<csrf-token> &nonce=<random-nonce> &code_challenge=<S256-of-verifier> &code_challenge_method=S256必填:client_id、redirect_uri、response_type=code、scope(必须包含 openid)。
公开客户端还必须提供 code_challenge 和 code_challenge_method=S256。
机密客户端可以同时省略这两个 PKCE 参数,但仍须在 /token 完成客户端认证。
空值、不完整的参数组合和不支持的 PKCE 方法都会被拒绝。
选填(建议带上):state、nonce。
下方示例仍使用推荐的 PKCE 流程。不使用 PKCE 的机密 OIDC 客户端必须保留 与本次登录事务绑定的 CSRF 和授权码注入防护,包括 RFC 9700 描述的 nonce 校验及额外防护要求。仅有客户端认证不能替代这些保护。
如果应用已知用户偏好的界面语言,可以传入可选的 ui_locales。请按偏好顺序填写以空格分隔的 BCP 47 语言标签。Sudomimus 会采用第一个支持的值(en-US 或 zh-CN);不支持的值会被忽略,不会阻止登录。这个提示只作用于本次登录,用户仍可在页面中切换语言。
生成有效的 PKCE 参数
Section titled “生成有效的 PKCE 参数”建议让 OIDC 客户端库生成 PKCE 参数。每次发起授权都要生成一组新参数,并把 verifier 与待完成的登录状态一起保存到回调完成为止。
如果需要自行生成:
code_verifier长度必须为 43–128 个字符,只能使用英文字母、数字、-、.、_和~。code_challenge是 verifier 的 SHA-256 摘要经过无填充 base64url 编码后的结果。S256 challenge 固定为 43 个字符,只能使用英文字母、数字、-和_。/authorize只发送code_challenge;在/token兑换授权码时,发送原始且未经修改的code_verifier。
不要重复使用 verifier,也不要把文档里的固定示例用于生产环境。Sudomimus 会拒绝格式不正确的参数和不匹配的 verifier/challenge。
一旦授权请求发送了 challenge,兑换时就必须提供匹配的 verifier,机密客户端也不例外。
如果授权时省略了 PKCE,/token 也必须省略 code_verifier;此时提供 verifier
会被拒绝,以防止降级攻击。
选择登录交互方式
Section titled “选择登录交互方式”多数应用可以省略 prompt 和 max_age。Sudomimus 会检查当前账户、凭据、应用、规则及同意状态,并可能复用同一应用记住的登录。复用后的 auth_time 仍是原始认证时间,不会把较早的认证变成一次全新认证。
| 参数 | 行为 |
|---|---|
省略 prompt |
复用符合条件的已记住登录;需要时继续交互式登录。 |
prompt=login |
要求重新认证。 |
prompt=select_account |
要求重新认证,让用户选择账户。 |
prompt=consent |
再次展示同意步骤,即使用户已经保存了声明共享选择。 |
prompt=none |
尝试复用登录,不显示登录界面;无法静默完成时返回交互错误。 |
max_age=0 |
要求重新认证。 |
正数 max_age |
只有原始认证距今不超过指定秒数,且当前检查全部通过时,才允许复用。 |
max_age 必须是非负十进制整数。prompt 可以用空格组合 login、select_account 和 consent;none 必须单独使用。
使用 prompt=none 时,应分别处理以下错误:没有可复用的有效认证时返回 login_required,需要用户同意时返回 consent_required,需要在浏览器补充必需账户资料时返回 interaction_required。用户准备好完成这些步骤后,再发起交互式授权请求。仅有有效的 id_token_hint 不能建立可复用的登录。
只有当应用需要在用户离开或关闭应用后继续刷新令牌时,才请求 offline_access。Sudomimus 会向用户展示一个默认未选中的独立离线会话选项。如果用户拒绝,登录仍会成功,但返回的 scope 不包含 offline_access,也不会签发 refresh token。应用应以返回的 scope 和是否存在 refresh_token 为准。
Sudomimus 会将用户跳转到 via.sudomimus.com,完成 Layer 1 允许的认证方式。认证和身份准入检查成功后,浏览器会携带 code、原始 state 和 iss=https://oidc.sudomimus.com 返回 redirect_uri。
Sudomimus 验证注册回调地址后发生的授权错误,会携带 error、error_description、原始 state 和同一个 iss 返回该回调。OIDC 库必须把 iss 与本次登录保存的 issuer 做精确比较,并在缺失或不一致时于兑换授权码之前拒绝响应。回调地址验证之前的错误则直接以 JSON 返回。请把 server_error 视为暂时性的服务端故障,让用户稍后重试,并且不要缓存协议错误响应。
2. 令牌交换
Section titled “2. 令牌交换”授权码有效期为 60 秒,且只能兑换一次。重复使用已兑换的授权码时,如果客户端认证、 回调地址和 PKCE 校验均通过,请求会被拒绝,并撤销该授权码产生的原会话及其刷新令牌。 如果兑换响应丢失,应重新开始授权流程,不要重试该授权码。其他登录会话不受影响。
向 /token 提交授权码。按照 OIDC 规范,请求体必须使用 application/x-www-form-urlencoded:
curl -X POST https://oidc.sudomimus.com/token \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=authorization_code" \ --data-urlencode "code=$AUTH_CODE" \ --data-urlencode "redirect_uri=https://app.example.com/oidc/callback" \ --data-urlencode "code_verifier=$PKCE_VERIFIER" \ --data-urlencode "client_id=my-app" \ --data-urlencode "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \ --data-urlencode "client_assertion=$CLIENT_ASSERTION_JWT"client_assertion 是使用客户端所选公钥来源对应的私钥签名的 JWT。必需声明包括:iss = client_id、sub = client_id、aud = 完整且精确的 token endpoint URL(生产环境为 https://oidc.sudomimus.com/token)、全新的 jti、iat 和 exp(与 iat 相差不超过 300 秒)。签名算法为 RS256。
curl -X POST https://oidc.sudomimus.com/token \ -u "my-app:$CLIENT_SECRET" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=authorization_code" \ --data-urlencode "code=$AUTH_CODE" \ --data-urlencode "redirect_uri=https://app.example.com/oidc/callback" \ --data-urlencode "code_verifier=$PKCE_VERIFIER"Basic 用户名就是 client_id,因此无需在表单中重复发送 client_id。标准 OIDC 客户端库默认使用这种请求形式。
curl -X POST https://oidc.sudomimus.com/token \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=authorization_code" \ --data-urlencode "code=$AUTH_CODE" \ --data-urlencode "redirect_uri=https://app.example.com/oidc/callback" \ --data-urlencode "code_verifier=$PKCE_VERIFIER" \ --data-urlencode "client_id=my-app" \ --data-urlencode "client_secret=$CLIENT_SECRET"curl -X POST https://oidc.sudomimus.com/token \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=authorization_code" \ --data-urlencode "code=$AUTH_CODE" \ --data-urlencode "redirect_uri=https://app.example.com/oidc/callback" \ --data-urlencode "code_verifier=$PKCE_VERIFIER" \ --data-urlencode "client_id=my-app"不发送客户端认证凭据。PKCE 证明客户端持有与授权请求 code_challenge 匹配的 verifier。
成功响应(JSON):
{ "access_token": "<JWT>", "token_type": "Bearer", "expires_in": 10800, "id_token": "<JWT>", "scope": "openid email profile"}id_token—— 由 Sudomimus 的平台级 OIDC 密钥签发,通过https://oidc.sudomimus.com/.well-known/jwks.json验证。它包含最小协议声明(iss、sub、aud、exp、iat、at_hash,以及可选的nonce、auth_time)和认证上下文(amr、acr)。个人资料从/userinfo获取。access_token—— 由应用的 token-signing 密钥签发,结构与 Connect 协议的访问令牌相同。refresh_token—— 仅在请求了offline_access且用户允许离线会话时返回。
3. Userinfo
Section titled “3. Userinfo”默认返回 JSON。将 OIDC ReturnRule 的 userinfoSignedResponseAlg 设置为 "RS256" 后,接口返回 application/jwt。请使用平台 JWKS 验证签名,并核对 issuer、client_id audience、subject 和有效期。签名响应包含相同的授权资料,不含 nonce 或令牌哈希,有效期不超过提交的 access token 或会话。退役的平台公钥应保留至 ID Token 和签名 UserInfo 均已过期。
curl https://oidc.sudomimus.com/userinfo \ -H "Authorization: Bearer $ACCESS_TOKEN"返回 scope 允许的声明:
{ "sub": "<sector subject>", "email": "<只在授予 'email' scope 时返回>", "email_verified": true, "name": "<只在授予 'profile' scope 时返回>", "given_name": "<只在授予 'profile' scope 时返回>", "family_name": "<只在授予 'profile' scope 时返回>", "picture": "<只在授予 'profile' scope 时返回>", "picture_animated": "<只在授予 'profile' scope 时返回>"}sub 是 扇区主体(sector subject) —— 按扇区维度、应用可见的标识符,与 id_token 的 sub 相同。请用它作为用户键。/userinfo 同时支持 GET 与 POST。
两种方法都优先使用 Authorization: Bearer 请求头。POST 也支持在
application/x-www-form-urlencoded 表单中传入一个 access_token。
不要同时通过请求头和表单传 Token,也不要重复表单参数;这些请求、空的表单
Token 以及 URL 查询参数中的 Token 都会返回 400 invalid_request。
JSON 和 GET 请求体不能用于传 Token。两种受支持的传递方式都执行相同的
Token 过期、实时会话和声明共享校验。
picture 与私有 claim picture_animated 遵循扇区头像交付约定;见头像声明与交付。
Claim state
Section titled “Claim state”如果应用需要当前策略与同意状态,请携带同一个 Bearer access token 调用 discovery
中的 claim_state_endpoint。它同时支持 GET 与 POST,并且不会返回资料值:
{ "sub": "<sector subject>", "claims": { "email": { "requirement": "OPTIONAL", "state": "GRANTED" }, "given_name": { "requirement": "OPTIONAL", "state": "GRANTED" }, "family_name": { "requirement": "OFF", "state": "UNKNOWN" }, "picture": { "requirement": "OFF", "state": "UNKNOWN" }, "picture_animated": { "requirement": "OFF", "state": "UNKNOWN" } }}只返回 email scope 与 profile scope 覆盖的条目。只有 openid scope 时,
claims 是空对象。
每个 id_token 都包含:
| 声明 | 含义 |
|---|---|
amr |
标准 Authentication Methods References 值。例如 passkey 是 ["hwk", "user"],邮箱验证码是 ["otp"]。 |
acr |
Sudomimus 的认证上下文字符串。例如 urn:sudomimus:acr:passkey 或 urn:sudomimus:acr:email-otp。 |
如果你的 RP 在敏感操作前需要确认用户刚才用了抗钓鱼方式登录,请检查 acr 是否为 urn:sudomimus:acr:passkey。Google、GitHub、Discord、Battle.net、X、Steam 和企业联合登录这类上游身份源都会映射到 amr: ["pwd"];需要区分具体来源时,请看 acr。
4. Refresh
Section titled “4. Refresh”如果请求了 offline_access、用户允许离线会话,并且响应中包含 refresh token,再到 /token 兑换:
curl -X POST https://oidc.sudomimus.com/token \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=refresh_token" \ --data-urlencode "refresh_token=$REFRESH_TOKEN" \ --data-urlencode "client_id=my-app" # 机密客户端再加 client_assertion刷新时应继续使用授权码兑换时选择的客户端认证方式。使用
client_secret_basic 时,通过 -u "my-app:$CLIENT_SECRET" 发送凭据,并省略
表单中的 client_id;使用 client_secret_post 时,在表单中同时发送
client_id 和 client_secret。
可以传入 scope,缩小会话当前已授权的范围。缩小对该会话永久生效,后续刷新不能恢复已移除的 scope。移除 offline_access 后不再签发 refresh token;移除 openid 后不再签发 ID Token。scope 集合不一致的并发刷新会被拒绝。刷新得到的 ID Token 不包含 nonce。
响应包含 refresh_token 时,用它替换已保存的旧令牌。按顺序执行刷新请求。短暂的轮换宽限期可以处理近乎同时发生的重试,但重试的实际 scope 必须与已完成的轮换一致。宽限期外重用旧令牌可能撤销会话。
5. 结束会话
Section titled “5. 结束会话”https://oidc.sudomimus.com/end-session ?id_token_hint=<id_token> &client_id=my-app &post_logout_redirect_uri=https%3A%2F%2Fapp.example.com%2F &state=<可选>/end-session 通知 OIDC 会话结束,并把用户跳转到 post_logout_redirect_uri(必须与注册过的某个 URI 完全匹配)。如果 id_token_hint 验证通过,并且其中的 aud 与当前 client 匹配,Sudomimus 会推进账户/应用会话权威,并吊销该账户在这个应用下的旧 ApplicationSession。
伪造、无效或已经无法对应到账户的 hint 不会阻止跳转,只是不会触发应用会话吊销。hint 可以是过期的,这样 RP 即使本地会话已经超时,也仍然可以发起一次干净的 logout。
如果你手上有某一个 refresh token,只想吊销这一条会话,请调用 Session API /logout。如果后端需要在不依赖 id_token_hint 的情况下吊销某个账户在应用内的所有会话,请调用 /revoke-all。详见 管理会话。
使用 OIDC 库
Section titled “使用 OIDC 库”绝大多数现代 OIDC 库(Node 的 openid-client、Python 的 authlib、Java 的 nimbus-jose-jwt 等)都能从 issuer URL 自动发现,并自动处理 PKCE、JWKS、令牌验证。这个 Node 示例支持 openid-client 6.x(使用 6.8.6 验证),采用注册为 token_endpoint_auth_method: "none" 的公共 PKCE 客户端:
import * as oidc from "openid-client";
const redirectUri = "https://app.example.com/oidc/callback";const configuration = await oidc.discovery( new URL("https://oidc.sudomimus.com"), "my-app", { redirect_uris: [redirectUri], response_types: ["code"], token_endpoint_auth_method: "none", }, oidc.None(), { execute: [oidc.enableNonRepudiationChecks], },);
export const startSignIn = async (savePendingSignIn) => {
const codeVerifier = oidc.randomPKCECodeVerifier(); const codeChallenge = await oidc.calculatePKCECodeChallenge(codeVerifier); const state = oidc.randomState(); const nonce = oidc.randomNonce();
await savePendingSignIn({ codeVerifier, state, nonce, });
return oidc.buildAuthorizationUrl(configuration, { redirect_uri: redirectUri, scope: "openid email profile", code_challenge: codeChallenge, code_challenge_method: "S256", state, nonce, });};
export const finishSignIn = async ( callbackUrl, consumePendingSignIn, createServerSideApplicationSession,) => {
const pendingSignIn = await consumePendingSignIn(); if (pendingSignIn === undefined) { throw new Error("OIDC sign-in state is missing or expired"); }
const tokens = await oidc.authorizationCodeGrant( configuration, callbackUrl, { pkceCodeVerifier: pendingSignIn.codeVerifier, expectedState: pendingSignIn.state, expectedNonce: pendingSignIn.nonce, }, ); const claims = tokens.claims(); if (claims?.sub === undefined) { throw new Error("The validated ID token did not contain sub"); }
const userinfo = await oidc.fetchUserInfo( configuration, tokens.access_token, claims.sub, );
await createServerSideApplicationSession({ userKey: claims.sub, refreshToken: tokens.refresh_token, });
return userinfo;};savePendingSignIn 和 consumePendingSignIn 表示与浏览器本次登录绑定的短期服务端存储。回调时只能消费一次 verifier、state 和 nonce。authorizationCodeGrant 会验证授权响应中的 discovery RFC 9207 issuer 与预期 state,并验证 ID-token nonce;配置的 non-repudiation check 还会通过 discovery 获得的 JWKS 验证 ID-token 签名。全部验证成功后,claims() 才会提供这些 claims。
createServerSideApplicationSession 表示应用自己的会话存储。请使用验证后的、限定于应用的 sub 作为用户键,把 refresh token 留在服务端,并且只向浏览器发送应用自己的 session cookie。不要把返回的 token response 序列化进 cookie。
令牌验证提醒
Section titled “令牌验证提醒”OIDC ID token 通过 oidc.sudomimus.com/.well-known/jwks.json 上的 JWKS 验证 —— 这是 OIDC 标准机制,OIDC 库会自动做。
但 /token 返回的 access_token 不是使用平台级 OIDC JWKS 验证的令牌。它是结构与 Connect 相同的应用专属访问令牌:payload sub 是配对用户键,sid 是 ApplicationSession,jti 是这个 token 实例。需要按 kid 使用 https://session-api.sudomimus.com/applications/{applicationAnchor}/jwks.json 验证。如果 OIDC 库无法为 access token 配置独立 JWKS,也可以将它视为不透明字符串,只通过 /userinfo 获取声明。详见令牌与验证。
纯 Implicit
Section titled “纯 Implicit”在客户端 allowedResponseTypes 中显式启用 id_token 或 id_token token,
并在 allowedGrantTypes 中允许 implicit。
applicationType="web" 时,所有已注册回调 URI 必须使用 HTTPS,且不能使用
localhost 或回环主机。native 客户端使用已注册的自定义 scheme 或精确的 HTTP
回环 URI,不接受 HTTPS 回调。
请求必须携带非空 nonce,并在验证返回 ID Token 的签名、issuer、audience
和有效期时一并校验。Implicit 默认通过 fragment 返回,也接受 form_post,
不接受 query。PKCE 参数会被忽略;offline_access 在同意流程前移除,
不会返回 refresh token 或授权码。
id_token 仅返回 ID Token,其中包含按 scope、当前策略和授权允许披露的身份声明。
id_token token 还返回 access token、token_type、expires_in 和获准的 scope;
需校验 ID Token 中与 access token 对应的 at_hash。两种响应都包含 iss,
并在请求提供 state 时原样返回。过期后需要重新授权。建议先按上文的 code
流程接入;启用 Implicit 前请确认部署环境的 Discovery 已公布该能力。
Hybrid
Section titled “Hybrid”显式注册所需的 Hybrid 响应类型,并在 allowedGrantTypes 中同时允许
authorization_code 和 implicit。web 客户端必须使用 HTTPS 回调,且不能使用
localhost 或回环主机。native 客户端遵循上文的 native 回调规则。
Hybrid 默认通过 fragment 返回,也接受 form_post,不接受 query。
所有包含授权码的公开客户端流程都必须使用 PKCE S256;前通道返回 ID Token 时,
请求必须携带 nonce,并由 RP 校验。
code id_token返回授权码和含c_hash的 ID Token。随后正常兑换授权码; 获准的offline_access仍需用户明确同意。ID Token 使用折叠后的访问令牌 TTL, 不受授权码较短的有效期限制。code token返回授权码和 AT。兑换不会创建第二个会话,而是在同一个不可刷新的 会话下返回 AT 和 ID Token。code id_token token还返回含c_hash和at_hash的 ID Token。 使用前须分别对照实际返回的授权码和 AT 校验这两个哈希。
携带 AT 的 Hybrid 在同意流程前移除 offline_access,不会签发 refresh token。
授权码兑换不会延长会话期限;兑换返回的 ID Token 只包含本次 AT 的 at_hash,
不包含 c_hash。请在各步骤校验 iss、state、签名、audience、有效期、
已提供的 nonce 和对应哈希。通过客户端认证的授权码重放会撤销该码对应的会话,
也会阻止先前 AT 的在线使用。授权失败后应重新发起流程;选择 Hybrid 前请确认
部署环境的 Discovery 已公布该响应类型。
Form Post 回调
Section titled “Form Post 回调”六种响应类型均可请求 response_mode=form_post。已注册回调必须使用 HTTP(S),并接受
application/x-www-form-urlencoded POST 请求体,并在处理凭据前验证
state 和 iss。同时校验 ID Token 的签名、audience、有效期、nonce 以及
适用的 at_hash、c_hash;收到授权码时通过 /token 兑换。
提供方会自动提交 HTML 表单,自动提交不可用时可点击 Continue 按钮。
不要记录该响应或回调请求体。如果 RP 使用 Cookie 关联授权请求,跨站 POST
回调所需 Cookie 应配置 SameSite=None; Secure;显式设置为 SameSite=Lax
或 SameSite=Strict 的 Cookie 不会随该回调发送。
受控动态注册
Section titled “受控动态注册”完整请求与响应见动态注册 API;签发与撤销操作见IAT 与 RAT 管理。
使用 Discovery 中的 registration_endpoint。注册必须携带 Initial Access Token(IAT)。
- 组织 OWNER 在 With → 组织 → Sector → OIDC 中申请 RP 主机审批。Sudomimus 工作人员批准主机。待审批的申请不授予注册权限。
- OWNER 在同一个 Sector OIDC 页面签发 IAT。选择可完成浏览器登录的 ACTIVE 应用模板、到期时间、有限配额、允许的 scope 和流程,并明确授权新客户端启用。
- RP 将 IAT 作为 Bearer 凭据发送到
POST /register。
向 POST /register 发送带 Bearer IAT 的 JSON,至少提供 redirect_uris。
默认值为 response_types=["code"]、grant_types=["authorization_code"]、
application_type="web"、pairwise subject、RS256 ID Token 和
token_endpoint_auth_method="client_secret_basic"。使用 private_key_jwt
必须提供 RSA 公钥 jwks 或 HTTPS jwks_uri,私钥留在 RP。不支持的算法和
加密选项会被拒绝。
成功响应为 HTTP 201,返回可用客户端的 client_id、
registration_client_uri 和独立的 Registration Access Token(RAT)。
共享密钥客户端还会收到 client_secret。不要把 IAT、RAT 或客户端密钥放进
浏览器存储、URL 或日志。RAT 可通过 GET registration_client_uri 读取当前
配置和当前共享密钥。它不能编辑注册配置或创建用户会话,但可以通过
DELETE registration_client_uri 删除自己的 OIDC 注册;此操作停用应用,并将其保留为管理资源。读取经过审计,
响应禁止缓存。规则和公钥通过 With 门户修改。
OWNER 可撤销资格、替换 RAT,或撤销整个组织的注册权限。IAT 到期、耗尽或
被撤销,不会自动撤销之前创建的客户端或 RAT。
RP 可以注册可选的 HTTPS initiate_login_uri,该 URI 不能包含片段。它指向
RP 接收第三方发起登录请求的入口,需支持 GET 和 POST。RP 检查 iss 后发起
正常的授权请求。创建响应和 RAT 读取在配置该 URI 时返回它。With 门户只读显示该 URI。
如需为仍有效的动态注册设置、修改或清除它,请联系 Sudomimus 支持团队。
多个回调 host 必须提供 HTTPS sector_identifier_uri,其 JSON 文档包含
每个精确回调 URI。文档 host 必须已获准绑定到组织的 Sector。修改回调时会
重新检查原有绑定及当前文档。Native 客户端可以注册自定义 scheme 或精确
HTTP loopback 地址;启用 Implicit/Hybrid 的 Web 客户端必须使用非 localhost
的 HTTPS 回调。自定义 scheme 不能作为浏览器 Form Post 的提交目标。
客户端名称遵循平台命名策略。提交的法律和首页 URL 作为描述性链接展示。 Logo 仅支持 PNG/JPEG/GIF/WebP,每张不超过 64 KiB;提供方会安全获取图片, 同意页不会从用户浏览器直接请求 RP 的图片服务器。
签名授权请求
Section titled “签名授权请求”可运行的示例见OIDC 高级接入与能力,密钥配置见RP 密钥配置与轮换。
Discovery 宣告支持 Request Object 后,已配置 RS256 的客户端可以通过
request 提交签名 JWT,或通过 request_uri 提交 HTTPS 引用。外层必须保留
client_id、response_type 和包含 openid 的 scope。JWT 中的值覆盖其他
外层参数;若包含内层 client/type,必须与外层一致。JWT 可以提供回调 URI。
可选的 iss、aud、exp、nbf、iat 在出现时会被校验。不支持无签名、
加密或嵌套对象。注册的 request_uris 非空时限制可用引用;否则可从允许的
公网 HTTPS 地址获取带有效签名的对象。密钥轮换和注册变更仍会触发实时权限
检查。具体可用能力以部署的 Discovery 为准。