Skip to main content
Documentation navigation

KAI AUTH / DEVELOPERS

Better Auth 1.7.1Updated Content: Simplified Chinese
View Markdown
On this page

额外身份验证

应用在高风险操作前将用户带回 KAI Auth 完成一次新的身份验证,再通过标准 OAuth 回调和签名令牌取得验证结果。

应用能看到什么

应用只能取得验证结果和本次验证时间,不会取得用户实际采用的高等级认证方式。

结果 对外表示 应用应如何处理
未完成认证 OAuth 错误,或始终没有收到有效回调 不执行受保护操作;允许用户重新发起
仅密码验证完成 kai_step_up.status: "password_only" 仅在业务明确允许密码结果时继续
高等级身份认证完成 kai_step_up.status: "verified" 完成令牌、用户和时间校验后,由业务判断是否继续

当前版本支持 TOTP 和 Passkey,其成功结果均为 verified;手机批准不在本次发布范围内。不会通过 amr、method、设备字段或不同的 acr 向应用区分实际方式。KAI 内部保留验证证据,用于正确执行策略、撤销和审计。

应用不能指定用户必须采用哪一种方式。KAI 根据账号当前配置提供验证选项:存在已配置的高等级方式时,只能使用这些方式;只有没有配置高等级方式且已有密码时,才允许额外密码验证。设备离线、浏览器不支持某种方式、验证失败或限流,都不会自动开放密码降级。账号没有可用方式时,本次验证无法完成。

verified 是 KAI 的结果分类,不单独承诺某个 NIST 等级、抗钓鱼能力、硬件保护能力或具体多因素组合。业务如果只接受高等级结果,应明确要求返回值为 verified。

发起请求

在已有业务登录会话下,创建一笔新的 Authorization Code + S256 PKCE 事务。保存这次事务的随机 state、nonce、PKCE verifier、预期用户的 iss / sub 和过期时间;不要复用首次登录的事务。

读取根路径 Discovery 的 authorization_endpoint,添加唯一的额外验证策略值:

GET /api/auth/oauth2/authorize
  ?client_id=YOUR_CLIENT_ID
  &response_type=code
  &redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fcallback
  &scope=openid
  &state=NEW_RANDOM_STATE
  &nonce=NEW_RANDOM_NONCE
  &code_challenge=BASE64URL_SHA256_NEW_VERIFIER
  &code_challenge_method=S256
  &acr_values=urn%3Akai%3Aacr%3Astep-up

openid 必须包含在 scope 中,请求也必须包含该应用登记的全部 requiredScopes。上例适用于仅将 openid 设为必选权限的应用;若另有必选 profile 或 email,也要一并请求,不需要的可选权限无需加入。redirect_uri 仍须是该应用登记的地址,public 客户端使用 PKCE,confidential 客户端在兑换令牌时按登记方式认证。需要业务 API 时另行申请对应 scope / resource,并遵守现有资源授权规则;额外验证本身不会扩展权限。

acr_values=urn:kai:acr:step-up 请求的是一次新的 KAI 额外验证。普通登录、已有高等级会话、prompt=login 或 max_age 本身都不能替代这笔请求的额外验证证明。可以同时使用 prompt=login 或 max_age;KAI 会保留原始请求绑定并完成恢复流程。

当前只支持上述单一 acr_values 值触发额外验证,不支持用 claims.id_token.acr 的 essential 请求代替,也不要拼接多个 ACR 值或具体因子名称。

已有 KAI 登录会话的用户进入独立验证页面,完成后沿原授权流程返回应用。验证保留当前会话,不额外创建一个登录会话,也不会更新原会话的认证时间。本次结果的 auth_time 独立记录实际证明完成时间。

验证交互从发起起最长有效十分钟;当前会话、原始签名请求或安全状态先失效时,交互也会提前失效。完成证明不会延长该期限。max_age 不能替代应用对最终证明时间的校验;应用应使用返回的 auth_time 检查自己的操作时效。

接收与校验结果

回调只返回标准 OAuth 授权码或错误。不要以 URL 中自行添加的 verified=true、页面提示或浏览器跳转成功作为验证证明。

  1. 校验回调 state、issuer 和本地事务有效期;有 error 时结束本次流程。
  2. 使用原始 redirect_uri 和 PKCE verifier,向 Discovery 的 token_endpoint 兑换一次性授权码。
  3. 按 ID token 校验规则验证签名、算法、iss、aud、exp 和本次 nonce。仅解码 JWT 不构成验证。
  4. 核对令牌的 iss / sub 与发起操作时保存的业务账号完全一致。用户换了账号时,不能给原账号的操作放行。
  5. 校验下面三个额外验证字段,并按业务规定的新鲜度窗口判断 auth_time。
{
  "acr": "urn:kai:acr:step-up",
  "auth_time": 1790000000,
  "kai_step_up": {
    "status": "verified"
  }
}
字段 JSON 类型 必须检查的内容
acr string 必须为 urn:kai:acr:step-up
auth_time number,非负整数 本次实际验证的秒级 Unix 时间;符合业务的新鲜度和时钟偏差要求
kai_step_up object 必须存在,不能用普通登录结果代替
kai_step_up.status "verified" 或 "password_only" 高等级要求只接受 verified;缺失或未知值不得视为成功

这些字段出现在本次授权的 ID token、适用的 JWT access token,以及活跃 access token 的 Introspection 结果中。JWT 的查询结果保留令牌中的声明,opaque token 的查询结果从原授权记录读取。refresh token 自身的查询结果不提供此证明;UserInfo 用于用户资料查询,也不作为额外验证结果接口。详细令牌适用范围见 claims。

业务应把通过校验的结果关联到原来的待处理操作,限制其有效时间和使用次数。身份验证结果不等于用户批准了某笔转账、金额或其他业务参数;这些内容仍须由应用展示、确认和授权。

未完成、取消与重试

情形 预期行为
用户主动取消 返回已登记的回调,携带 OAuth 错误,不产生成功验证证明
用户关闭页面、断网或事务过期 可能没有回调;应用应结束等待并按未完成处理
prompt=none,用户未登录 返回 login_required,不弹出交互页面
prompt=none,缺少本次有效证明 返回 interaction_required,不能把旧会话当作新证明
过程中安全配置、会话或权限发生变化 旧流程可能失效,重新发起验证;不要自动改用密码
授权提交遇到临时并发冲突 KAI 页面要求重新检查或重试;应用只有拿到并校验最终成功结果后才能继续

本次证明只属于原始应用、用户、浏览器会话和授权事务。改变 state、nonce、PKCE、resource 或回调等参数,不能借用旧证明。授权码只能消费一次,证明也不能用于签发第二个授权码。

刷新与其他登录流程

刷新令牌保留原验证结果和原 auth_time,不会执行新的验证,也不会延长验证证明的新鲜度。需要更新证明时,应新建一笔额外验证事务。后来在同一浏览器完成验证,不会把以前的普通授权或 Device 授权升级为 verified。

Device Authorization 用于 CLI 等设备取得登录授权;目前不能通过给 Device 请求添加 acr_values 来获得本页的额外验证结果。Auth CLI 使用独立的 oauth step-up 命令发起本页的授权码流程,并执行相同的回调、签名、用户和时间校验。

/oauth/step-up 页面与 /api/oauth/step-up/* 是 KAI 自己的浏览器交互入口,使用当前浏览器会话和同源保护。第三方应用不得拿 OAuth access token 调用这些接口、抓取 Cookie 或代替用户提交验证凭据;第三方集成入口始终是 Discovery 中的授权端点。