认证与 key 安全

平台有两套互不相通的认证,搞清楚它们就不会踩坑:

平面凭据用在哪怎么来
机器侧Authorization: Bearer sk-meow-…/v1/* 全部 API控制台签发
人侧mb_session httpOnly cookie控制台页面与 /console/*/auth/me登录自动种下

API key 不能用来登录控制台,cookie 也不能用来调 /v1/*

Bearer key 怎么用

每个 API 请求都带上请求头:

code
Authorization: Bearer sk-meow-xxxxxxxx…

安全纪律(平台侧承诺)

安全纪律(你这一侧的建议)

控制台会话(人侧)

原生 App 模式(GitHub OAuth,ADR-0025)

上面两套认证都是给浏览器用的:控制台页面跑在浏览器里,cookie 能自动种下。但原生 App(手机端用系统浏览器 Custom Tab 打开登录页)拿不到这个 cookie,也跳不回 App 里——所以 GitHub 登录额外有一条「app 模式」,让 App 也能登 GitHub 换到一把 API key。

只有 GitHub 登录需要这条。邮箱 OTP 登录原生可以直接用——POST /auth/email/start 发码、POST /auth/email/verify 验码,验码响应直接带回 mb_session 会话 cookie(原生 HTTP 客户端自己就能收下、不像 Custom Tab 那样拿不到),App 持这个会话再 POST /console/keys 签一把 API key 即可。整条都是普通 HTTP 请求,不依赖浏览器跳转,所以不需要 app 模式这条深链流程。

三步换 key

  1. App 本地先生成一对 PKCE 值:一个高熵随机串 code_verifier(自己保存,别发出去),和它的「指纹」code_challenge = base64url(sha256(code_verifier))

  2. 用系统浏览器(Custom Tab)打开:

    code
    GET /auth/github?app=1&code_challenge=<上面的 challenge>&code_challenge_method=S256

    用户在 GitHub 授权页点同意后,云端不种 cookie,而是 302 跳一个深链回你的 App:

    code
    meowbot://auth/callback?code=<一次性 code>

    (meowbot:// 是 App 约定的自定义 scheme,App 注册它来接收回跳。)

  3. App 拿 code + 当初的 verifier 换 key:

    code
    POST /auth/app/exchange
    Content-Type: application/json
    
    { "code": "<深链带回的 code>", "code_verifier": "<第 1 步保存的 verifier>" }

    成功返回:

    json
    { "api_key": "sk-meow-…", "tenant_id": "…" }

    这把 api_key 就是机器侧 Bearer key,之后照常 Authorization: Bearer sk-meow-…/v1/*明文只在这一次返回,务必当场存好。

为什么要 PKCE

深链(meowbot://…)在手机上理论上可能被同机装的别的 app 抢注截获。光有 code 不够安全——所以换 key 时必须同时交出第 1 步那个只有你自己知道的 code_verifier,云端验证 sha256(verifier) 和当初发起时存的 code_challenge 对得上,才发 key。这样即使 code 被别人截走,没有 verifier 也换不到 key。这是 OAuth 原生应用的标准做法(PKCE,RFC 7636,本平台只接受 S256,不接受 plain)。

一次性 code 的纪律

常见错误码

含义处理
401key 缺失 / 无效 / 已撤销检查 Authorization 头;必要时重签 key
429触发该 key 的限流Retry-After 头(秒),等够再发;详见限流与用量