授权码与 PKCE
通过浏览器完成用户登录和授权,再以一次性授权码换取令牌。
发现服务
读取 https://auth.kai.com/.well-known/openid-configuration,要求返回的 issuer 与配置的 https://auth.kai.com 完全一致。使用文档返回的 authorization、token、JWKS 和 UserInfo URL,不猜测 /api 路径。
创建授权事务
每次登录生成高熵随机 state、nonce 和 PKCE code_verifier。code_challenge 是 verifier 的 SHA-256 摘要经 base64url 编码,code_challenge_method 固定 S256。将事务保存到当前浏览器或服务端会话,设置短有效期,消费后立即删除。
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%20profile%20email
&state=RANDOM_STATE
&nonce=RANDOM_NONCE
&code_challenge=BASE64URL_SHA256_VERIFIER
&code_challenge_method=S256
这是纯登录示例,故不携带 resource。若要访问资源服务器,在用户授权阶段发送已获准的准确 resource identifier,并在兑换时保持该授权目标,不能在拿到 code 后扩展资源或 scope。
要求重新验证
确实需要用户重新证明身份时使用标准 prompt=login,或用 max_age 限定最近认证时间。Auth 对已有登录会话提供独立的重新验证与取消流程;完成密码、OTP、Passkey 或 Lark 所需的全部验证后,原地更新会话证据和 auth_time,保留 SID 与已有应用授权,不额外创建会话。普通登录不应无条件强制重新验证。
prompt=none 保持静默语义,无法满足条件时返回协议错误,不打开交互页面。账号安全设置改变导致的令牌撤销与普通重新验证不同,见令牌校验与 claims。
高风险操作的额外验证
应用需要在高风险操作前再次确认当前用户时,创建新的授权码事务,在原有 openid、state、nonce、PKCE 参数之外添加:
acr_values=urn:kai:acr:step-up
这个值请求 KAI 的额外验证策略,不指定验证方式,也不代表某个统一的 MFA 等级。KAI 按账号已配置的安全方式选择流程:只要配置了高等级安全因子就不能退回密码;账号没有配置这类因子时才允许密码。设备暂不可用、验证失败或被限流不会解除该限制。没有可用验证方式时,用户需要先解决账号访问问题。
已登录用户在独立页面完成验证,过程保留当前浏览器会话。普通登录本身不能替代这次额外验证。验证凭据绑定本次应用、用户、浏览器会话和完整授权事务,只能签发一次授权码;其他应用或另一笔 state / nonce 事务不能借用。可同时使用 prompt=login 或 max_age,整个恢复与授权流程保留其绑定,不要求用户反复登录。
回调仍使用应用登记的 redirect_uri,仍须完成标准授权码兑换和 ID token 校验。随后额外检查:
acr必须等于urn:kai:acr:step-up;kai_step_up.status为verified时表示已完成高等级额外验证,为password_only时只表示完成密码验证;由业务方决定密码结果是否足够;auth_time是这次证明的秒级时间,业务方应检查自己的新鲜度窗口,并确认iss/sub与当前业务账号一致。
应用不会获得具体因子、设备或 amr 明细。用户主动取消时返回标准 OAuth 错误;关闭页面、断网或超时可能没有回调,应用应按未完成处理。这些情况都不会签发表示成功的 ID token。prompt=none 在缺少本次已完成证明时返回 interaction_required,未登录时返回 login_required。
刷新令牌不会执行新验证,也不会更新这次结果的 auth_time。需要更新证明时必须重新发起上述授权事务。此结果只证明身份验证完成,不等于用户批准了转账、修改资料等具体业务操作;业务操作及其参数仍由应用自行确认和授权。
完整请求示例、三种结果、字段类型、失败处理和 CLI 边界见额外身份验证。
接收回调
只在本应用登记的回调接收响应。拒绝缺失、重复、不匹配或过期的 state;检查授权响应中的 iss 与预期 issuer 一致。处理 error(例如用户拒绝)时也验证事务。不要把 code、令牌或完整回调 URL 发送到日志或分析服务。
验证成功后立即消费事务,用与授权请求完全相同的 redirect_uri 和原 code_verifier 兑换 code。授权码只可使用一次,失败后重新发起登录。
兑换令牌
向 Discovery 的 token_endpoint POST application/x-www-form-urlencoded:
grant_type=authorization_code
client_id=YOUR_CLIENT_ID
code=AUTHORIZATION_CODE
redirect_uri=https://app.example.com/oauth/callback
code_verifier=ORIGINAL_VERIFIER
public 客户端不发送 secret;confidential 客户端另外使用 HTTP Basic 认证。不要在前端复制 confidential secret,也不要为了方便测试改变现有应用的客户端类型。
响应包含 access_token、token_type、expires_in;有效 scope 含 openid 时提供 ID token,允许 refresh grant 且获准 offline_access 时提供 refresh token。检查实际返回的 scope,资源策略可能缩小权限。
验证身份
用 JWKS 验证 ID token 签名,检查 iss、aud(本应用的 client ID)、exp、nonce,必要时按 OIDC 规范检查 azp 和 at_hash。仅解码 JWT 不等于验证。使用经过验证的 iss 与 sub 识别账号,不以邮箱作为永久主键。
向 UserInfo 发送 Authorization: Bearer ACCESS_TOKEN。其 sub 必须与 ID token 一致。profile、email 控制可读的用户信息,不保证 ID token 内包含所有资料字段。
刷新与退出
refresh token 只在用户已授权 offline_access 时使用;客户端需要支持刷新轮换,成功后使用新返回的 refresh token。不要并行刷新同一授权链,也不要把原始 refresh token 显示在测试报告中。
退出应用和退出 Auth 会话是不同动作。跨应用退出、令牌撤销及回跳请按退出与授权撤销实现。