05. OAuth 登录(ChatGPT / Gemini / Claude)

CPA 通过 OAuth 拿到上游账号的访问权限。流程是:

  1. 在容器里启动一个临时登录子进程,监听本地某端口(Codex=1455,Gemini=8085,Claude=54545 等)
  2. 它输出一个授权 URL,你在浏览器打开 → 登录上游账号 → 同意授权
  3. 上游服务回调 http://localhost:<port>/...,把 token 投递给容器
  4. 子进程把 token 写到 auth-dir/<provider>-<email>-*.json,CPA 主进程的 file watcher 自动加载

第 3 步的回调是写死的 localhost——这就是远程服务器的难点,需要 SSH 隧道把本机的 localhost 转发到服务器。

通用前提

  • CPA 容器已经在跑,docker ps 能看到 cli-proxy-api
  • mihomo 已切到合适地区的节点(04
  • config.yamlproxy-url 已指向 mihomo

步骤 1:本机开 SSH 隧道

本地电脑新开一个终端:

# Codex / ChatGPT
ssh -L 1455:127.0.0.1:1455 root@你的服务器IP
 
# Gemini
ssh -L 8085:127.0.0.1:8085 root@你的服务器IP
 
# Claude(端口看你的 docker run 暴露了哪个,常见是 54545)
ssh -L 54545:127.0.0.1:54545 root@你的服务器IP

也可以一条命令转发多个端口:

ssh -L 1455:127.0.0.1:1455 -L 8085:127.0.0.1:8085 -L 54545:127.0.0.1:54545 root@你的服务器IP

这个终端保持开着,关掉隧道就断。SSH 第一次连会问 fingerprint,输 yes 回车继续。

步骤 2:在服务器上执行登录命令

回到服务器终端,在已经运行的 CPA 容器里 exec 一个登录进程:

# Codex / ChatGPT
docker exec -it cli-proxy-api ./CLIProxyAPI --codex-login --no-browser
 
# Gemini(具体 flag 名以 --help 输出为准)
docker exec -it cli-proxy-api ./CLIProxyAPI --login --no-browser
 
# Claude
docker exec -it cli-proxy-api ./CLIProxyAPI --claude-login --no-browser

--no-browser 必须加,否则程序会试图调用宿主机不存在的浏览器。

如果不确定 flag 名:

docker exec cli-proxy-api ./CLIProxyAPI --help

步骤 3:完成授权

子进程会输出一段 URL,复制到本地浏览器打开:

  1. 登录对应账号(ChatGPT / Google / Anthropic)
  2. 点同意授权
  3. 浏览器跳转到 http://localhost:1455/...(或 8085/54545)
  4. 因为 SSH 隧道,本地 localhost 实际转发到了服务器容器
  5. 服务器看到回调 → 写入凭据 → 显示 ... authentication successful

步骤 4:验证

# 凭据文件已生成
ls /root/CLIProxyAPI/auths/
# 应该看到 codex-xxx@xxx.com-free.json 之类
 
# CPA 已经热加载
docker logs --tail 5 cli-proxy-api
# 应该有 "auth file changed (CREATE): codex-xxx, processing incrementally"

调用一下:

curl -s http://127.0.0.1:8317/v1/models \
  -H "Authorization: Bearer 你的api-key" | python3 -m json.tool | head -30
 
curl -s http://127.0.0.1:8317/v1/chat/completions \
  -H "Authorization: Bearer 你的api-key" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-5","messages":[{"role":"user","content":"say hi"}]}' | python3 -m json.tool

返回正常 JSON 就说明从客户端到上游全链路通了。

关于回调 IP / hosts 替换

如果不想搞 SSH 隧道,理论上也可以:

  1. 在本机 /etc/hosts 添加 127.0.0.1 你的服务器域名,把回调劫到本地——不行,因为回调地址是写死的 localhost,根本不查 DNS。
  2. 在浏览器跳转时手动localhost:1455 改成 服务器IP:1455——可以,但要求服务器对应端口开放且没有 IP 限制;安全性差,不推荐

SSH 隧道是干净的方案:临时性、加密、不需要开任何外网端口。

多账号

CPA 支持挂多个 OAuth 账号,重复执行步骤 2-3 用不同账号即可:

docker exec -it cli-proxy-api ./CLIProxyAPI --codex-login --no-browser
# 用账号 A 完成
docker exec -it cli-proxy-api ./CLIProxyAPI --codex-login --no-browser
# 再用账号 B 完成
ls /root/CLIProxyAPI/auths/
# codex-A@x.com-free.json
# codex-B@x.com-pro.json

config.yamlrouting.strategy 控制怎么用这些凭据:

  • round-robin(默认):轮询
  • fill-first:先把第一个用到限额再切下一个

凭据失效 / 重新登录

凭据偶尔会因为上游账号风控/到期而失效,日志会出现 refresh failed 一类的报错。处理:

# 找到出问题的凭据
ls /root/CLIProxyAPI/auths/
 
# 直接删掉,CPA 会自动卸载
rm /root/CLIProxyAPI/auths/codex-xxx.json
 
# 重新登录
docker exec -it cli-proxy-api ./CLIProxyAPI --codex-login --no-browser

下一步:06-management-panel.md 启用管理面板。