原生 SSO 验收客户端
# 原生 SSO 验收客户端
fago-cli auth native 通过系统浏览器执行 OIDC Authorization Code + S256 PKCE,当前进程读取本人和设备会话、刷新并退出。access/refresh 只在内存,不写入配置、钥匙串或磁盘,也不接受外部 token、口令或 verifier 参数。当前已在 macOS 系统浏览器与本地 ZITADEL v4.20.0 验证三种内容协议;Linux 提供 xdg-open 入口但尚无真实桌面验收,Windows 明确不支持。
这是一条有限会话验收命令,尚不提供通用 SDK、长期凭据缓存或任意 API 调用。后续已用两个独立Web应用完成真实IdP单点登录和跨应用签名统一退出,见浏览器SSO;本命令的真实IdP证据仍为同一原生应用三协议,见 M5 记录。
# 准备客户端与绑定
平台先登记当前 realm 的 native 或 desktop 客户端,grant 为 authorization_code,再配置已审核的 provider 和既有主体外部绑定。member 使用独立会员主体;admin 使用租户管理员主体;platform 使用平台主体且不填租户编码。不能靠 email 或同名账号自动合并身份。管理入口见 客户端注册 和 提供方与绑定。
上游须登记公共原生应用、code grant、S256 和 auth_method=none。部署信任档案须明确 allow_native_loopback=true,授权回跳为 http://127.0.0.1:<登记端口>/oidc/<realm>/<租户数值ID或0>/<provider编码>/callback。命令先绑定真实随机端口,再由服务端只替换批准回跳的端口;路径、IPv4 地址与身份定位不变。上游须支持 RFC 8252 的 loopback 临时端口规则,不用 localhost 或自定义 scheme 替代。
API 使用已受信 HTTPS。私有 CA 可通过重复的 --ca-file 增加公开证书,始终校验证书和主机名;文件须为稳定的普通文件,不能是符号链接或可被组/其他用户写入的文件。客户端不读取后端私钥、数据库 DSN 或 Redis 凭据,也不使用环境代理。
# 运行一次完整会话
在完整源码树构建时,先从外层仓库根目录执行 source scripts/go-env.sh,再进入 fago/fago-server/apps/fago-cli/ 构建。下面使用已构建的二进制;尖括号内容替换为实际非秘密定位:
fago-cli --json auth native \
--api-url https://api.example.invalid \
--realm member \
--client-id <已登记客户端编码> \
--provider-id <provider数值ID> \
--tenant-code <租户编码> \
--suite rsa-aes \
--actions me,sessions,refresh,me,logout-local
系统浏览器出现既有 IdP 账号登录页面;认证完成后,loopback 页面只显示“登录回调已收到,请返回命令行”。命令随后使用原 verifier 一次换码,验证当前 realm/client 的本人和设备响应。默认步骤与上例相同,最后明确只撤销本地会话。错误路径、错误 state、重复参数或重复回调不能换码。
--suite 必须明确匹配服务端:rsa-aes、sm2-sm4 或开发用 plain,发现/加密失败不会降级。授权回跳的 loopback HTTP 本身不需要 --allow-loopback-http;该标志只为本机开发 API/IdP 的字面 loopback HTTP 例外,不能放宽其他 HTTP 或 TLS 校验。生产继续要求 HTTPS 与内容加密。
# 步骤与退出判定
| 步骤 | 通过条件 |
|---|---|
me | 实际 API 返回本人合同,并符合当前 realm/client |
sessions | 实际设备列表恰有一个当前 native/desktop 会话,client 一致 |
refresh | 当前 refresh 只发送一次并轮换;不自动重试 |
wait:60s | 有界等待,供操作者在另一个应用完成操作;单次最多10分钟 |
expect-rejected | 使用仍持有的 access 实际请求 API,观察401;无本地 token 不能算通过 |
logout-local | 服务端确认本地撤销,输出 local_only |
logout | 本地撤销后准备并打开 IdP RP退出,输出 redirect_ready 只表示已发起 |
最多20步;--login-timeout 为30秒至10分钟,默认5分钟;--session-timeout 为1至60分钟,默认30分钟。脚本结束、失败或 Ctrl+C 会在独立5秒期限尝试本地退出,再清除内存和连接;网络中断时不能保证服务端撤销已经提交,须使用会话管理确认或撤销。已有绝对期限和后台到期清理继续生效。
原生 RP 退出只携带标准 id_token_hint,不包含动态 post_logout_redirect_uri 或 state,不会再建立原生退出回调。unavailable 表示本地已退、上游准备失败,命令以失败结束;不可把浏览器打开、返回页面或单个会话401当作所有应用已退出的证明。跨应用结论需要真实 IdP 签名通知以及每个应用当前会话的检查。
# 故障与输出
输出只含步骤、状态、realm/client 与本地内存状态,不输出凭据、完整个人资料、授权 URL、code 或底层错误链。退出码0表示指定步骤完成,2表示参数错误,1表示业务或依赖失败。
登录超时、IdP拒绝或换码失败后,从新的登录重新开始;不得重放旧code/state/verifier。刷新结果不明时禁止再次刷新旧材料,但保留证明用于有限本地退出。首次改密或自然口令到期仍遵循本地主体限制,命令不提供改密流程,也不能绕过租户停用、客户端停用、绑定撤销或当前权限栅栏。