Auth CLI:让 Agent 配置登录
Auth CLI 帮助开发者在本机登录 KAI 管理账号,让 Agent 管理组织、项目和应用,并为业务应用生成 OAuth/OIDC 接入配置。
安装与运行
命令名为 kai-auth,包名为 @kai/auth-cli,需要 Node.js 24.3.0 或更高版本。当前可从仓库构建本地安装包;以下流程不依赖 npm 上已发布的包。
在仓库的 Yarn 开发环境中构建:
yarn workspace @kai/auth-cli build
yarn workspace @kai/auth-cli pack --out /tmp/kai-auth-cli.tgz
将生成的安装包放到开发者本机,然后运行:
npm install -g /tmp/kai-auth-cli.tgz
kai-auth --help
CLI 0.2 不再使用 Playwright,不安装或操控 Chromium,也不读取浏览器 Cookie。需要先部署包含 CLI API 的 Auth 后端和数据库迁移;旧服务会返回 CLI_LOGIN_UNAVAILABLE,不会自动退回 Cookie 登录。
源码开发可用 yarn auth:cli --help 构建并运行 CLI。使用对应平台的 Node 环境,不要复用其他平台的 node_modules。
开发者授权,终端调用 API
# 普通电脑:系统浏览器 + Authorization Code / S256 PKCE
kai-auth login --profile default --origin https://auth.kai.com --name "开发工作站"
# SSH、容器等无界面终端:在另一台设备输入终端显示的设备码
kai-auth login --profile remote --origin https://auth.kai.com --device
# 仅需要读取资源
kai-auth login --profile inspect --origin https://auth.kai.com --read-only
kai-auth status --profile default --json
桌面登录启动只监听 127.0.0.1 的随机端口,再打开系统浏览器。用户完成正常登录及明确授权后,CLI 通过 PKCE 兑换专用管理令牌。--no-open 可以只显示地址,需在同一电脑打开;另一台电脑请使用 --device。
设备授权显示一个 10 位终端码,用户到 Auth 页面输入并确认。终端名称由请求方提供,不是身份保证;仅批准自己发起的登录请求。轮询遵守服务器的 interval、slow_down 和 Retry-After,不会把限流当作设备码失效。
CLI 使用独立、不透明的 Bearer 凭据。management:read 允许读取,management:write 允许在已有角色权限内修改资源。业务应用的 OAuth access token 不具备管理权限;组织、项目角色、冻结状态和敏感操作额外验证仍由后端检查。平台管理与个人安全接口没有因此开放给 CLI。
access token 最长 5 分钟,CLI 在运行命令时按需轮换 refresh token;整个授权最长 7 天,并且不超过批准时原始登录的到期时间。刷新不延长该期限,组织会话策略继续生效。并发命令通过 profile 文件锁串行刷新;旧 refresh token 被重放会使整个授权失效。账号安全版本变化或撤销管理会话也会使授权失效。
后续命令默认使用 default profile,可通过 --profile NAME 区分账号或环境。--origin 仅用于首次登录,后续请求始终使用保存的地址,不跨域发送凭据。已有 profile 请先 logout,或选择新名称。
个人中心新增 CLI 授权,可逐个撤销终端。退出网页不会退出 CLI;kai-auth logout 会先撤销 CLI 授权,再删除本机凭据。网络失败时保留文件,便于重试撤销。
旧版 Cookie profile 不会被导入:先到个人中心撤销对应会话,删除旧 profile 文件,再使用新 CLI 登录。应用自己的 OAuth 登录及 oauth step-up 接口不受影响。
完整示例:创建应用并生成接入文件
以下示例使用 jq 提取命令输出中的 ID。它创建 public Web 应用,通过 Authorization Code + PKCE 登录,不需要 client secret。将回调地址替换成业务应用实际使用的 HTTPS 地址。
先创建组织和项目;已有资源可用 list 查询并直接使用返回的 ID。
ORGANIZATION_ID=$(
printf '%s' '{"name":"Example Team","slug":"example-team"}' |
kai-auth organizations create --stdin --json |
jq -er '.data.id'
)
PROJECT_ID=$(
printf '%s' '{"name":"Example App","slug":"example-app"}' |
kai-auth projects create --organization "$ORGANIZATION_ID" --stdin --json |
jq -er '.data.id'
)
创建应用的 JSON 使用与管理 API 相同的字段:
cat > application.json <<'JSON'
{
"name": "Example Web",
"clientType": "public",
"applicationKind": "web",
"accessMode": "authenticated_users",
"scopes": ["openid", "profile", "email"],
"requiredScopes": ["openid"],
"optionalScopes": ["profile", "email"],
"signInMethods": ["authorization_code"],
"redirectUris": ["https://app.example.com/oauth/callback"],
"postLogoutRedirectUris": ["https://app.example.com/signed-out"]
}
JSON
APPLICATION_ID=$(
kai-auth applications create \
--organization "$ORGANIZATION_ID" \
--project "$PROJECT_ID" \
--file application.json --json |
jq -er '.data.application.id'
)
kai-auth init \
--organization "$ORGANIZATION_ID" \
--project "$PROJECT_ID" \
--application "$APPLICATION_ID" \
--redirect-uri https://app.example.com/oauth/callback \
--directory ./my-app --json
kai-auth config show --directory ./my-app --json
kai-auth config env --directory ./my-app --json
kai-auth doctor --directory ./my-app --json
每一步失败后先处理错误,再继续下一步。authenticated_users 允许非组织成员登录;仅对组织成员开放时改为 members_only。profile 和 email 在此示例中是可选权限,应用必须处理用户未授权这些信息的情况。
init 读取已登记应用,在目标目录创建:
| 文件 | 用途 |
|---|---|
kai-auth.json |
公开的应用接入配置,供 CLI 和 Agent 读取 |
.env.example |
环境变量示例,不会自动加载进业务应用 |
KAI_AUTH.md |
供开发者与 Agent 使用的接入说明 |
生成操作不覆盖已有文件;发生冲突时先审查现有内容,或选择新目录。--redirect-uri 必须是该应用已经登记的回调;有多个回调时必须显式选择,命令不会自动修改回调白名单。配置中的 issuer 来自 Discovery,可以与登录使用的服务 origin 不同。
.env.example 包含 KAI_AUTH_ORIGIN、KAI_AUTH_ISSUER、KAI_AUTH_CLIENT_ID、KAI_AUTH_CLIENT_TYPE、KAI_AUTH_SCOPES 和 KAI_AUTH_SIGN_IN_METHODS;浏览器授权应用还包含 KAI_AUTH_REDIRECT_URI。confidential 应用的 KAI_AUTH_CLIENT_SECRET 仅为空白占位。生成文件不包含管理会话或实际 client secret。
配置生成后,Agent 还需要结合业务应用的框架实现 OIDC 登录入口、回调、PKCE、state、nonce、令牌验证和应用自己的会话。使用 Discovery 中的端点,按照Authorization Code + PKCE和令牌校验与 claims完成接入;生成文件不等于业务应用已经支持登录。
给 Agent 的任务示例
开发者完成本机 kai-auth login 后,可以提供以下任务:
使用 kai-auth --json 为当前项目接入 KAI 登录。先检查 status 和组织、项目、
应用列表,确认目标资源;需要创建或更新时先读取对应 schema,再提交 JSON。
为选定应用运行 init,阅读 KAI_AUTH.md,并按本项目的框架实现标准 OIDC
Authorization Code + PKCE、回调校验与应用会话。使用 config show/env 获取
公开配置,运行 doctor 后,再验证业务应用真实登录、回调和退出流程。
client secret 只从安全文件交给服务端环境,不放入前端代码或命令输出。
本页的机器可读地址为 /docs/auth-cli/index.md;也可以通过 /llms.txt 查找其余接入资料。
应用侧的额外身份验证
kai-auth oauth step-up 为应用发起 OAuth 额外身份验证。它与下文用于删除项目等管理动作的 kai-auth step-up 是不同流程,不读取或转发管理 profile 的 Bearer 凭据,也不直接调用 KAI 的私有验证接口。
当前命令适用于已登记的 native / public 应用,必须启用 Authorization Code、允许 openid,并配置精确的本机回调,例如 http://127.0.0.1:8765/oauth/callback。该回调需要事先加入应用白名单,并由 init --redirect-uri 写入配置。命令不会放宽回调校验、自动增加白名单或把端口替换为随机值;端口被占用时先处理冲突。Web 和 confidential 应用按其运行环境接入标准授权码流程;Device-only 应用必须先登记并启用 Authorization Code,不能通过向 Device 请求添加 acr_values 获取额外验证结果。
kai-auth doctor --directory ./native-app --step-up --json
kai-auth oauth step-up \
--directory ./native-app \
--expected-sub CURRENT_USER_SUBJECT \
--max-proof-age 300 \
--timeout 600 \
--json
--expected-sub 必填,取当前业务已验证身份的 sub,不能填写邮箱、昵称,也不能根据本次回调临时更换预期用户。issuer 从接入配置固定读取。
CLI 先启动只监听本机的回调,再打开系统浏览器。用户在 KAI 页面亲自完成登录和额外验证;CLI 使用新的随机 state、nonce 与 S256 PKCE 兑换授权码,并验证 ID token 签名、issuer、audience、nonce、用户、额外验证策略及时间。它请求 openid 及应用登记的全部必选权限,不额外请求可选权限,也不把这次证明保存为管理登录会话。若必选权限包含 offline_access,命令会在发起授权前报配置错误;该命令不申请长效访问授权,需要调整应用的必选权限配置后重试。
--max-proof-age默认 300 秒,限制实际证明的新鲜度;刷新令牌不能重新计算此时间。--timeout默认 600 秒,限制本次命令等待时间;取消、超时或中断不会被当作验证成功。--no-open只把授权入口写到 stderr,供用户在能够访问本机回调的浏览器中打开;它不自动批准、不提交密码,也不是远程无界面认证。--proof-file NEW_PRIVATE_FILE显式要求把通过校验的签名 ID token 保存到新的私有文件,权限为0600,不覆盖已有文件。普通命令输出不包含 ID token、access token、refresh token、授权码或 Cookie。
成功结果只区分 verified 与 password_only,不返回 TOTP、Passkey 等实际方式;当前版本不包含手机批准。password_only 表示密码证明校验成功,不表示已经满足高等级要求;业务只接受高等级验证时仍须要求 verified。普通 JSON 输出是 CLI 的本机验真报告,不是可以转交给任意服务器的签名凭证;其他服务需要验证专门面向自己的 OAuth 证明,不能盲目信任这份 JSON 或面向 CLI client ID 的 ID token。
使用 --json 时,stdout 只输出一份机器可读结果;进度写入 stderr。成功示例:
{
"ok": true,
"data": {
"status": "verified",
"issuer": "https://auth.kai.com",
"subject": "CURRENT_USER_SUBJECT",
"acr": "urn:kai:acr:step-up",
"authTime": 1790000000,
"expiresAt": 1790000300
}
}
authTime 与 expiresAt 均为秒级 Unix 时间;后者是 ID token 的到期时间,不会延长 --max-proof-age 规定的证明有效窗口。显式保存证明时,结果另含 proofFile 路径。未完成、超时或验证失败时返回 ok: false 和脱敏的 error.code / error.message,并以非零状态退出;不会返回成功状态或未校验的令牌。
doctor --step-up 只检查本地配置、Discovery 和这条流程需要的公开能力,不会替代真实用户验证,也不保证远端应用登记没有变化。完整登录、取消、错误回调、时间过期和同一账号核对仍应实际验收。
命令与输入契约
| 命令 | 主要参数与用途 |
|---|---|
login |
--profile NAME --origin URL;可选 --device、--no-open、--read-only、--name |
status、logout |
查看或清除所选 profile 的本机登录状态 |
organizations list |
查看当前账号可用的组织 |
organizations get/create/update/delete |
get、update、delete 使用 --organization UUID |
projects list/get/create/update/delete |
必须指定 --organization UUID;get、update、delete 另需 --project UUID |
applications list/get/create/update/delete |
必须指定 --organization UUID --project UUID;get、update、delete 另需 --application UUID |
step-up start/prove/send-otp/verify-otp/cancel |
通过 --file 或 --stdin 提供 JSON;除 start 外还需 --transaction UUID |
oauth step-up |
应用侧额外验证;--directory DIR --expected-sub SUBJECT,可选时间限制、--no-open、--proof-file NEW_FILE |
schema NAME |
输出指定输入的 JSON Schema |
init |
指定组织、项目、应用 UUID;可选 --directory DIR --redirect-uri URL |
config show/env |
读取 --directory DIR 下的接入配置或生成环境变量说明 |
doctor |
检查 --directory DIR 下的配置及服务端 Discovery;--step-up 追加本机 OAuth 额外验证检查 |
create、update 使用 --file PATH 或 --stdin 二选一读取 JSON。输入在发请求前通过 API 的 Effect Schema 验证;服务器仍会检查当前数据和权限。可读取以下 schema:
kai-auth schema organization-create --json
kai-auth schema organization-update --json
kai-auth schema project-create --json
kai-auth schema project-update --json
kai-auth schema application-create --json
kai-auth schema application-update --json
kai-auth schema project-delete --json
kai-auth schema step-up-start --json
kai-auth schema step-up-prove --json
kai-auth schema step-up-send-otp --json
kai-auth schema step-up-verify-otp --json
kai-auth schema step-up-cancel --json
JSON Schema 用于了解字段结构;跨字段限制也会在实际命令执行时验证。例如 requiredScopes 与 optionalScopes 必须同时给出、不重叠,并合起来等于 scopes;native 应用必须为 public。回调和客户端规则见应用登记与回调。
delete 必须显式提供 --confirm,值等于待删除对象的 UUID。删除项目还需要通过 --file 或 --stdin 提供有效的 project-delete 再次验证凭证。凭证绑定具体动作、对象、会话与版本并由服务端验证,--confirm 不能代替它。
删除项目的再次验证
使用相同的 profile 发起、验证并消费 step-up 事务,不能从另一个浏览器登录会话复制凭证。先为目标项目启动事务:
kai-auth step-up start --stdin --json <<JSON
{"action":"project_remove","resourceId":"$PROJECT_ID"}
JSON
读取响应中的 data.transaction。transactionId 用作后续的 --transaction;每次提交使用最新返回的 transactionRevision 作为 expectedTransactionRevision。allowedMethods 列出可用方式,otpTargets 给出可用联系人的 ID 和脱敏地址。
| 命令 | 输入 JSON 字段 |
|---|---|
step-up prove |
expectedTransactionRevision、method(password 或 totp)、proof(密码或六位 TOTP) |
step-up send-otp |
expectedTransactionRevision、method(email_otp 或 sms_otp)、contactId |
step-up verify-otp |
expectedTransactionRevision、challengeId、code(六位验证码) |
step-up cancel |
expectedTransactionRevision |
开发者通过受保护的输入文件或 stdin 提供密码、TOTP 或验证码,避免放入命令行参数、shell 历史、普通项目文件或日志。不要把证明输入交给无关工具。只选服务器允许的验证方式;这里的管理 step-up 命令不直接执行 Passkey,需要 Passkey 时在控制台完成管理操作。应用侧 oauth step-up 则将验证交给 KAI 浏览器页面。
例如,把验证输入安全保存在项目以外的私有文件后:
kai-auth step-up prove --transaction "$TRANSACTION_ID" \
--file "$PRIVATE_PROOF_INPUT_FILE" --json
密码或 TOTP 验证使用 prove。邮件或短信验证先调用 send-otp,再使用其返回的 challengeId 和最新事务版本调用 verify-otp。仅当返回 data.transaction.state 为 ready 时,data.proof 才是可用于删除的请求体;否则继续按事务状态处理,不能自行填造凭证。
将 ready 响应中的 data.proof 保存为权限受限的临时 JSON 文件后,可以完成删除:
kai-auth projects delete --organization "$ORGANIZATION_ID" \
--project "$PROJECT_ID" --confirm "$PROJECT_ID" \
--file "$PRIVATE_DELETE_PROOF_FILE" --json
凭证只能使用一次并有有效期。事务不再需要时使用 step-up cancel;失败或版本变化时读取错误并重新确认当前状态,不重复提交旧凭证。
机密应用与本机凭据
confidential 应用只适用于能保守秘密的服务端。创建这类应用时,CLI 将一次性 client secret 写入本机的新文件,权限为 0600,结果只返回文件路径。默认文件放在 CLI 配置目录,也可用 applications create --secret-file PATH 指定一个不存在的文件。将秘密通过服务端的秘密管理机制提供给应用,不能放进前端 bundle、版本库或普通日志。
CLI 配置目录依次采用 KAI_AUTH_CONFIG_DIR、$XDG_CONFIG_HOME/kai-auth、~/.config/kai-auth。profile 凭据与业务项目文件分开保存,应只允许所需的本机开发者或 Agent 访问。kai-auth logout --profile NAME 先撤销整个 CLI 授权,再清除该 profile;服务端连接失败时保留文件供重试。刷新令牌不要跨机器复制,否则并发轮换可能导致授权被撤销。异常退出后残留的 <profile>.json.lock 必须确认没有命令仍在使用后再删除。业务应用的 OIDC 退出流程见退出与撤销。
JSON 输出与诊断范围
HTTP 错误在普通输出和 --json 中保留稳定错误码与 requestId;服务端提供等待期限时,JSON 的 error.retryAfterSeconds 是非负整数。脚本应等待后重试,写操作未收到确认时先读取状态,不立即重复提交。错误码和 429 处理见错误码与请求诊断。
所有命令支持 --json,stdout 只输出一个 JSON 对象,进度发往 stderr。成功形态为 {"ok":true,"data":...};失败形态为 {"ok":false,"error":{"code":"...","message":"..."}},有请求编号时附带 requestId。doctor 的检查失败额外在 data 中保留逐项报告,错误码为 DIAGNOSTICS_FAILED。失败退出码非零。Agent 应同时检查退出码和 ok,解析时不要合并 stderr 与 stdout。
命令不会打印 access token、refresh token 或 client secret。doctor 校验本地接入配置和实时 Discovery,包括 issuer、协议端点、scope、grant 和 PKCE 等配置。每项报告 pass、fail 或 skipped;它不重新核对远端应用当前的登记状态,也不执行真实 OAuth 登录。
通过检查只说明已检查的条件符合要求,不代表完整授权、回调、换取令牌或应用会话已经验证。真实登录仍需在业务应用中完成,并检查用户拒绝授权、可选权限未获准、回调错误和退出等结果。
使用诊断信息协作
CLI 报错时保留稳定 error.code、error.requestId 和发生时间,按照错误码文档处理重试。应用自己的 OAuth 问题可在所属项目的接入诊断查询;项目权限和平台权限分别校验,CLI 的 management:read 不会自动取得平台故障或其他项目的诊断。
当前版本没有 kai-auth diagnostics 子命令,诊断控制台使用网页会话。不要把 CLI 管理 access/refresh token、profile 文件或 Cookie 发到诊断上报端点。可选应用上报只使用 authorize 明确请求后返回的 kai_diagnostic_token,用于该次业务 OAuth 流程;它不是 CLI 管理凭据,也不授予查看诊断的权限。
Agent 协助排错时可以读取公开文档和已授权项目的安全导出;不要要求用户粘贴凭据、完整 OAuth 回调或第三方账号资料。导出包含 requestId/flowId 和项目内匿名标识,应按项目资料保管,不公开发布。