令牌校验与 claims
区分 ID token、access token、令牌响应和 Introspection,并按实际 JSON 类型读取组织权限。
五个 KAI 扩展字段
| 字段 | JSON 类型 | 含义 |
|---|---|---|
organization_id |
string | 应用所属组织 ID |
project_id |
string | 应用所属项目 ID |
organization_role |
"owner"、"admin"、"developer"、"member" 或 null |
用户在应用所属组织中的角色 |
access_mode |
"members_only" 或 "authenticated_users" |
应用准入方式 |
access_version |
number(整数) | 组织访问策略版本;不是字符串或布尔值 |
这五个字段由组织与项目归属、当前成员关系和应用 metadata 计算,出现在成功令牌响应、ID token、JWT access token,以及适用的活跃 Introspection 结果中。无效令牌可能只返回 {"active": false},客户端不能要求错误响应也带齐这些字段。
authenticated_users 模式下非成员可以合法登录,organization_role: null 是有效值。不要为了通过解析把它改成 member。扩展字段描述应用所属租户,不意味着用户有权访问其他租户或任意管理 API。
JWT 授权与认证凭据
资源 JWT access token 还包含五个由 Auth 维护的内部声明:
| 字段 | JSON 类型 | 含义 |
|---|---|---|
kai_consent_id |
string(UUID) | 本次令牌所属的原始用户授权 |
kai_consent_version |
number(非负整数) | 授权版本;缩减 scope 或 resource 时递增 |
kai_auth_revision |
number(非负整数) | 签发时账号的密码认证修订号 |
kai_factor_revision |
number(非负整数) | 签发时账号的安全因子修订号 |
kai_policy_revision |
number(非负整数) | 签发时账号的二步验证策略修订号 |
这些字段用于 Auth 的在线校验,不替代标准签名、issuer、audience 和 scope 检查,也不是资源服务器自行授予权限的依据。它们不承诺出现在 ID token 或普通登录资料中。
标准字段
| 字段 | 类型与检查 |
|---|---|
iss |
string;必须等于配置的 issuer |
sub |
string;用户稳定标识,与已验证 issuer 一起使用 |
aud |
string 或 string[];ID token 面向 client ID,access token 面向资源 |
exp、iat、auth_time |
number;秒级 Unix 时间,auth_time 仅在适用时出现 |
scope |
access token / Introspection 中空格分隔的 string |
nonce |
ID token 中与本次授权事务一致的 string |
sid |
适用时的会话标识,用于退出关联 |
client_id、azp |
access token / Introspection 中的发放客户端标识 |
JWT access token 使用 typ: at+jwt。API 不得接受 ID token 代替 access token。使用受信任 Discovery 的 jwks_uri 验证签名,并检查算法、有效期、issuer、audience 和所需 scope;不从未验证 token 中选择任意远端密钥地址。
额外验证结果
使用 acr_values=urn:kai:acr:step-up 并完成额外验证后,ID token、适用的 JWT access token 及活跃 access token 的 Introspection 结果包含以下公开字段(不包含 refresh token 自身的 Introspection):
{
"acr": "urn:kai:acr:step-up",
"auth_time": 1790000000,
"kai_step_up": { "status": "verified" }
}
kai_step_up.status 只有 verified 和 password_only 两个成功值。前者表示完成高等级额外验证,后者只表示完成密码验证;两者不能混用。主动取消通过 OAuth 错误返回;关闭页面或超时可能没有回调,应用应按未完成处理,不存在“未完成但成功发放的证明”。不会对外发放此次验证的具体方式、设备或 amr。acr 标识 KAI 策略,不表示应用选择了某个具体因子,也不应解读为统一的 MFA 等级。
acr 是 string,auth_time 是非负整数,单位为 Unix 秒;kai_step_up 是 object,其 status 是上述两个字符串值之一。缺失字段、未知状态或不同 acr 都不能当作成功的额外验证。业务还须检查验证时间与当前业务账号的 iss / sub,不能仅检查 status。
| 返回位置 | 是否提供额外验证结果 |
|---|---|
| 本次授权的 ID token | 是,先验证签名和标准 OIDC 声明 |
| 本次授权的 JWT access token | 是,资源服务器仍需验证自己的 audience 和 scope |
| 活跃 access token 的 Introspection | 是;JWT 保留已校验声明,opaque token 从原授权记录读取 |
| Token endpoint 响应的 JSON 顶层 | 否,结果位于令牌内 |
| refresh token 自身的 Introspection | 否 |
| UserInfo | 否,用于读取已授权的用户资料 |
这些字段来自授权码签发时冻结的证明,refresh 保留原结果与原 auth_time。之后浏览器进行其他验证不会升级此前的授权链。普通 OAuth / Device 授权不会因同一个账号做过额外验证就附带成功结果。UserInfo 不提供额外验证结果,不能代替对签名证明的校验。完整请求、回调与结果校验见额外身份验证。
资料字段与 UserInfo
openid 提供 OIDC 身份语义,profile 和 email 控制 UserInfo 可见的资料。客户端以实际返回结果和 scope 为准,不假定 ID token 含 name、picture 或 email。UserInfo 的 sub 必须和 ID token 一致。
email scope 或显式 claims 请求必须授权对应字段,UserInfo 才会返回已验证的 email(string)或 email_verified(boolean)。单独请求其中一个字段不会自动获得另一个。仅手机号注册的账号没有已验证邮箱,因此这两个声明会缺省;即使请求了 email scope,也不能假定它们存在。Auth 自有的 /api/me 与原生会话接口使用 user.email: null、emailVerified: false 表示这种情况。接入应用应以 issuer 和 sub 标识用户。
撤销与策略更新
组织暂停后阻止新的访问与令牌操作;恢复组织不会恢复旧 consent 或授权链。成员或应用归属变化也可能使已有授权失效。离线 JWT 验证只观察签名与声明,已签发 JWT 在其剩余有效期内仍可能有效,当前默认上限为五分钟。
Auth 的 UserInfo 和 Introspection 会检查原始 consent、授权版本、scope、audience 和当前来源会话的三项认证修订号。删除 consent、缩减权限,或撤销来源会话后,旧资源 JWT 在这些在线端点失效;重新授权或恢复已删除的权限不会复活旧令牌。
修改密码、安全因子或二步验证策略会撤销已有授权码、Device Code 授权、access token 和 refresh token,包括经验证后保留当前会话的个人安全操作。因子或策略修改保留 consent 与自动登录偏好,但应用需要重新发起授权获取新令牌;密码修改还会清除 consent。普通 RP 重新验证不改变这些修订号,不撤销其他应用的授权。
部署此凭据契约后,未携带上述完整声明的旧资源 JWT 会被在线 UserInfo 和 Introspection 拒绝。若原刷新授权链仍有效,可刷新获得新令牌,否则重新授权。升级不会因此删除账号或浏览器会话;离线验证仍可能接受旧 JWT 直到原 exp 到期。
令牌里的 access_version 是发行时的策略版本,不会自动更新。若资源服务器要求即时撤销,必须设计在线状态或版本检查,不能只缓存该字段并宣称实时撤销。授权撤销和退出行为见退出与授权撤销。