登录与授权

个人访问令牌、设备授权与 MCP PKCE,附实测的请求与响应。

更新于 10月28日

下面几种流程都在验收中完整走通,包括真实 Claude Code 与 Codex 客户端的登录。学校所在的 OneAI 开放了 API 才可使用。

选择认证方式

方式 使用者 audience
个人访问令牌(PAT) 脚本、oneai auth import-token 创建时选 public-api 或 mcp
设备授权 oneai login(client oneai-cli) public-api
浏览器 OAuth + S256 PKCE MCP 客户端 mcp

浏览器会话不会变成客户端凭据:同时带 Cookie 和 Bearer 令牌的请求返回 401。audience 不能混用。mcp 令牌打公开 API,或 public-api 令牌打 /mcp,都返回 403 external.audience.denied。

个人访问令牌

教师在 OneAI 设置里创建 PAT,选择 audience、scope 和 1 到 90 天的有效期(默认 30 天)。创建前要再输一次密码。这次重新验证 5 分钟内有效,只能用于一个令牌;复用会返回 403 external.reauth.required。令牌只在创建响应里出现一次(下面是摘录),OneAI 只保存它的哈希。

{ "id": "afc20e2e-e29e-4018-8a45-9c03618ef247", "clientId": "oneai-pat", "audience": "public-api",
  "scopes": ["profile:read", "classes:read", "grades:read"], "expiresAt": "2026-11-21T09:17:17.094Z", "token": "oneai_pat_…" }
curl -H "Authorization: Bearer $ONEAI_TOKEN" "$ONEAI_ORIGIN/api/public/v1/me"

设备授权

curl -X POST "$ONEAI_ORIGIN/oauth/device_authorization" -d client_id=oneai-cli \
  --data-urlencode "scope=profile:read classes:read" --data-urlencode "resource=$ONEAI_ORIGIN/api/public/v1"
{ "device_code": "…", "user_code": "XXXX-XXXX", "verification_uri": "$ONEAI_ORIGIN/activate",
  "verification_uri_complete": "$ONEAI_ORIGIN/activate?user_code=XXXX-XXXX", "expires_in": 600, "interval": 5 }

教师打开地址,核对用户码,查看客户端、工作区与 scope 后输入密码同意。同时客户端向 /oauth/token 提交 grant_type=urn:ietf:params:oauth:grant-type:device_code,带 client_id、device_code 和 resource:

  • 每次轮询前等 interval 秒。authorization_pending 表示尚未同意,按原间隔继续等;
  • slow_down 表示轮询太早,间隔再加 5 秒。实测中,申请后立即轮询就得到 slow_down;
  • access_denied(教师拒绝,或学校关闭了客户端)和 invalid_grant(设备码已用过)都是终态,除非教师要求,不要重新发起。

同意后返回令牌,访问令牌有效 600 秒:

{ "access_token": "oneai_access_…", "refresh_token": "oneai_refresh_…", "token_type": "Bearer", "expires_in": 600,
  "scope": "profile:read classes:read" }

刷新时提交 grant_type=refresh_token、client_id、refresh_token 和 resource,每次刷新都会换发新的 refresh 令牌。重放旧的 refresh 令牌返回 invalid_grant,并撤销整条链:较新的 refresh 令牌同样失效,较新的访问令牌返回 401。

MCP 浏览器授权

MCP 客户端不带令牌时得到 401,WWW-Authenticate 头引向资源元数据与授权服务器。client_id 是一份 Client ID Metadata Document 的 HTTPS 地址。OneAI 只批准精确的来源,远程元数据不能扩大学校政策或 scope。授权时用 response_type=code、code_challenge_method=S256、resource=$ONEAI_ORIGIN/mcp 和 state,回跳带回 code、state 与 iss。授权码 60 秒内有效,只能用一次。兑换时提交 grant_type=authorization_code、client_id、code、redirect_uri、code_verifier 和 resource。verifier 不对或授权码重放都返回 invalid_grant。OneAI 登录时不在线拉取客户端元数据,而是采用审过的 Claude Code 与 Codex 元数据副本,客户端改了元数据时由人工更新;client_id 不在这份清单里的客户端得到 invalid_client。两个客户端的 MCP 配置见「MCP 接入」。

撤销与学校政策

教师在设置里查看和撤销授权。被撤销的令牌在下一次调用就返回 401 external.token.invalid。学校关闭外部客户端后,令牌返回 403 external.school.disabled,刷新返回 access_denied。学校重新打开后,原令牌恢复可用。目前没有 /oauth/revoke 端点,客户端不能自行吊销令牌。不要把令牌写进命令参数、截图、模型上下文或日志。

登录与授权 · 开发者文档