令牌与验证
Sudomimus 签发三种令牌,由不同的密钥签名、通过不同的机制验证。本页是令牌验证与字段内容的唯一参考 —— 每个 claim 的含义,以及决定字段取值的规则。
| 令牌 | 签发者 | 签名密钥 | 验证方式 | 携带的内容 |
|---|---|---|---|---|
| Access token | Connect、Session API、Native API 或 OIDC(/redeem、/refresh、/direct-issue/*、/token) | 应用当前生效的 token-signing 私钥 | Session GET /applications/{applicationAnchor}/jwks.json 按 kid 选择 | Payload iss、aud、sub、sid、jti、iat、exp |
| Refresh token | Connect、Session API、Native API 或 OIDC(/redeem、/refresh、/direct-issue/*、/token) | 应用当前生效的 token-signing 私钥 | 与 access token 相同 | Payload iss、aud、sid、jti、iat、exp、rotationVersion |
| OIDC ID token | OIDC(/token) | 平台级 OIDC 签名密钥 | oidc.sudomimus.com/.well-known/jwks.json | sub、iss、aud、exp、iat、at_hash、nonce?、auth_time?、amr?、acr? |
三者都是用 RS256(RSA-2048)签名的 JWT。
Access token 与 refresh token
Section titled “Access token 与 refresh token”这是你的应用后端日常打交道的两种令牌。两者都由 Sudomimus 用与你应用绑定的密钥对签发 —— 每个应用都有自己独立的一对,轮换一个应用的密钥不会影响其他应用。
应用使用 Session API 发布的专属 token-signing JWK Set 验签。推荐流程:
- 请求
GET https://session-api.sudomimus.com/applications/{applicationAnchor}/jwks.json,并按响应的Cache-Control缓存。 - 收到 JWT 后先把内容视为不可信数据:要求
alg === "RS256"、typ符合预期、aud === applicationAnchor、kid非空且exp有效。 - 从 JWK Set 中精确选择与 header
kid相同的 JWK 并验签;只有验签通过后才能信任任何 claim。 - 如果找不到
kid,立即刷新一次 JWK Set 后再拒绝。不要根据不可信的 audience 拼接请求地址;应使用配置好的应用 anchor 与 Session API origin。
JWK Set 可能同时包含预发布的下一把密钥、当前签名密钥,以及仍需验证存量令牌的退役密钥。已撤销或超过保留期的密钥不会发布,这个重叠窗口保证轮换不会让仍在有效期内的令牌失去验签能力。
紧急撤销会立即从新的 Session JWKS 响应中移除退役密钥。已缓存该公钥的验证端可能在已公布缓存有效期的剩余时间内继续接受其签名,最长持续到上次成功获取后 300 秒。这种有界收敛是离线 JWT 验证的一部分;不要将撤销理解为对所有遵循缓存规则的验证端都会瞬时生效。当敏感操作需要当前的实时会话权限时,除了验签,还应使用 Session POST /introspect。
应用令牌 JWKS 是每个应用独立的,并与平台级 OIDC JWKS 分离。验证端只会获得配置的 applicationAnchor 所属密钥;轮换某个应用不会影响其他应用。
typ header
Section titled “typ header”Sudomimus 的 access token / refresh token JWT 用 typ 明确令牌类型:
- Access token:
typ: "vnd.sudomimus.application-access+jwt" - Refresh token:
typ: "vnd.sudomimus.application-refresh+jwt"
当 typ 与端点预期的凭据类型不符时,应当直接拒绝。
TTL 区间
Section titled “TTL 区间”| 默认值 | 最小值 | 最大值 | |
|---|---|---|---|
| Access token | 3 小时 (10800s) | 60 秒 | 7 天 (604800s) |
| Refresh token | 30 天 (2592000s) | 1 天 (86400s) | 365 天 (31536000s) |
规则上和单次请求上的 TTL 覆盖都受这套区间限制。当多个 TTL 同时命中(例如一条 Layer 1 规则 + 一条 Layer 3 请求约束),Sudomimus 会取其中的最小值;如有必要,access TTL 会被缩短,确保不超过 refresh TTL。
Access token 字段
Section titled “Access token 字段”受保护 header 只包含 alg、kid、typ。标准 JWT claim 与会话绑定放在 payload 中。sub 是配对的扇区主体,也是应用应使用的用户键;sid 是稳定的逻辑 ApplicationSession id;jti 标识某一个 bearer 实例。应用令牌不携带个人资料或原始账户 id。
// JWT header{ "alg": "RS256", "kid": "<signing-key identifier>", "typ": "vnd.sudomimus.application-access+jwt"}// JWT payload{ "iss": "https://sudomimus.com", "aud": "<applicationAnchor>", "sub": "<sector subject>", "sid": "<application session identifier>", "jti": "<access token identifier>", "iat": <epoch>, "exp": <epoch>}| Claim | 含义 |
|---|---|
typ | 总是 "vnd.sudomimus.application-access+jwt"。任何不匹配的令牌都应拒绝。 |
sub | 应用可见的扇区主体(sector subject),即按(账户 × 扇区)生成的不透明标识符(例如 sub_9SQ5535CRWNDDM2T)。应用应使用该值标识用户。它在同一扇区内对同一用户保持稳定,但可以由用户轮换,并且在不同扇区之间互不相同。请将其视为不透明值,不要解析。 |
sid | 逻辑 ApplicationSession 的稳定标识。同一次登录签发的 access/refresh token 在轮换期间共享它。它不是用户 id。 |
jti | 这个 access-token 实例的唯一标识。它与 sid 不同,并在每次签发新 access token 时改变。 |
iss | Sudomimus 的 HTTPS 应用令牌 issuer。 |
aud | 签发本令牌的应用的 applicationAnchor。 |
iat、exp | 标准 JWT 签发时间 / 过期时间,单位秒(epoch)。 |
Refresh token 字段
Section titled “Refresh token 字段”Refresh token 使用同样的最小 header。它的 payload 不含 sub 或任何个人资料;sid、jti 与 rotationVersion 标识一个精确的已签名 refresh 版本。
// JWT header{ "alg": "RS256", "kid": "<signing-key identifier>", "typ": "vnd.sudomimus.application-refresh+jwt"}// JWT payload{ "iss": "https://sudomimus.com", "aud": "<applicationAnchor>", "sid": "<application session identifier>", "jti": "<refresh token version identifier>", "iat": <epoch>, "exp": <epoch>, "rotationVersion": 1}rotationVersion 是正整数,每次成功轮换加一。请把新返回的 refresh JWT
作为一个完整的不透明凭据保存;不要根据 sid、jti 或版本自行构造或修改令牌。
Sudomimus 会先验签,再按 sid 强一致读取 ApplicationSession,随后精确匹配
应用、jti 与版本,之后才会轮换;内部 session 会单独证明当前 subject authority。
Application UserInfo
Section titled “Application UserInfo”使用 Authorization: Bearer <accessToken> 调用 GET https://session-api.sudomimus.com/userinfo,获取当前经同意门控的个人资料。响应总是包含 sub,并可能包含 email、email_verified、name、given_name、family_name、picture 与私有 claim picture_animated。这些字段是实时、可替换的个人资料;用户主键只能使用 payload sub。
如果只需要实时的策略要求与同意状态、不需要资料值,请携带同一个 Bearer token
调用 GET https://session-api.sudomimus.com/claim-state。它使用 email、
given_name、family_name、picture 与 picture_animated 作为 claim key。
OIDC ID token
Section titled “OIDC ID token”当应用作为 OIDC 接入方 集成时,/token 端点会在 access_token 之外再返回一个 id_token。这个 ID token 由平台级 OIDC 签名密钥签发(不是应用专属密钥),通过 https://oidc.sudomimus.com/.well-known/jwks.json 上的 JWKS 验证。
ID token 字段遵循 OpenID Connect 标准:
{ "iss": "https://oidc.sudomimus.com", "sub": "<sector subject>", "aud": "<client_id>", "exp": <epoch>, "iat": <epoch>, "at_hash": "<access-token hash>", "nonce": "<来自 /authorize(如有)>", "auth_time": <epoch(如有)>, "amr": ["<认证方式>"], "acr": "<认证上下文>"}| Claim | 含义 |
|---|---|
iss | 总是 "https://oidc.sudomimus.com"。 |
sub | 扇区主体 —— 与配对的 access token payload 中 sub 相同的(账户 × 扇区)值。在你所属扇区内对同一用户稳定,可轮换,且不同扇区之间不同。 |
aud | 接入方的 OIDC client_id。 |
exp、iat | 标准 JWT 时间字段,单位秒(epoch)。 |
nonce | 首次签发时回显接入方在 /authorize 时传入的值。按 OIDC core 1.0 §12.1,refresh-token grant 不会再回显。 |
auth_time | 用户实际完成认证的时间(秒)。refresh-token grant 会保留原值。 |
at_hash | 把 ID token 与配对的 access token 绑定。 |
amr、acr | 认证方式引用与认证上下文。 |
OIDC 签名密钥会定期轮换;JWKS 在轮换期间会同时发布当前生效和最近退役的两把密钥,保证验签连续可用。
OIDC 流程下的 access token
Section titled “OIDC 流程下的 access token”OIDC /token 同时返回与普通应用流程相同的最小 access_token,不携带 scope 相关个人资料。应用使用每应用 Session JWKS 验签,并从 discovery 中的 OIDC /userinfo 获取 scope 控制的资料。
完整接入方流程(含 /userinfo 和 /end-session)见 OIDC 接入方。
- Connect 协议 + Session API(access / refresh token 通过每应用 Session JWKS 验签):你的应用后端直接和 Sudomimus 对接。最低开销,无额外跳转。
- OIDC(ID token 通过 JWKS 验签):你的应用已经接了某个标准 OIDC 库,或者你需要让第三方系统作为接入方。Sudomimus 此时扮演 IdP。
同一个应用通常只用其中一种 —— 没必要两种都接。