Codex 从中转 API 切到 ChatGPT 订阅 OAuth,并保留全部历史会话

October, 15th 2026 8 min read • Markdown •

背景

我的 Codex CLI 一直通过一个 CRS 中转 API 使用,所有历史会话、项目配置、MCP 都在默认的 ~/.codex/ 里。后来开了 ChatGPT 订阅,想把默认命令改成订阅 OAuth 登录。

最省事的做法是新建一个空的 CODEX_HOME,重新登录。但这样 cdx resume 就看不到原来的会话了。我当时本地有 5,000 多条会话,分布在 200 多个项目目录里,不想丢。

最后的结果:原目录原地切换,迁移前后会话记录逐条比对,ID、项目目录、rollout 路径、provider 字段的缺失和变化都是 0。

环境:macOS,Codex CLI 0.162.x。

最终的命令布局

我把三种用法拆成三个独立实例,互不污染:

命令数据目录用途
cdx~/.codex/默认入口,ChatGPT 订阅 OAuth,保留全部历史
cdxs~/.codex-sub/另一套保留的实例
cx~/.codex-crs/偶尔还要用中转 API 时用,独立 API Key

别名写在 zsh 配置里:

zsh
1234
CODEX_NODE=22.23.1
alias cdx="mise exec node@${CODEX_NODE} -- codex --yolo"
alias cdxs="CODEX_HOME=$HOME/.codex-sub mise exec node@${CODEX_NODE} -- codex --yolo"
alias cx="CODEX_HOME=$HOME/.codex-crs mise exec node@${CODEX_NODE} -- codex --yolo"

cdx 没有显式设 CODEX_HOME,用的是默认目录。要注意:如果当前 shell 已经 export 过别的 CODEX_HOME,cdx 会进错实例。不确定的时候写成 CODEX_HOME="$HOME/.codex" cdx。

cx 是单独配的,没复制 cdx 的历史和 MCP。中转模式要回来,用它就行,不用动主实例。

保留历史的关键:provider 名字不动,只改地址

翻了一下历史会话,每条记录的 model_provider 都是 crs。如果把 provider 换成新名字,旧会话和新配置就对不上了。

所以我保留 crs 这个标识,只把它指向的地址改成 ChatGPT 官方端点:

toml
12345678
model_provider = "crs"
model = "gpt-6.1-sol"

[model_providers.crs]
name = "crs"
base_url = "https://chatgpt.com/backend-api/codex"
wire_api = "responses"
requires_openai_auth = true

这只是相关字段,不要拿去覆盖整份 config.toml,其他设置保持原样。另外,顶层字段(model_provider、model)必须放在第一个 [表] 之前,否则 TOML 会把它们归到上一个表里。

改完之后,crs 只是个历史兼容的名字,实际请求已经直接发到官方,不再经过中转。

整个过程没改历史数据库,也没重写任何会话文件。

操作步骤

1. 先备份

完整备份数据目录,再单独存一份 SQLite 一致性快照。活跃的数据库不能只复制主文件,WAL 里可能还有没合并的数据。运行中的 socket 是进程通信端点,不用备份。

zsh
1
sqlite3 ~/.codex/state_5.sqlite ".backup '$HOME/codex-backups/state_5.consistent.sqlite'"

(数据库文件名以你本机实际为准。)

2. 改 provider 地址

按上一节改 config.toml。顺序不能反:必须先把地址改成官方端点,再做 OAuth 登录。否则 ChatGPT 的 OAuth token 会被发到原来的中转地址。

3. 浏览器授权

zsh
12
CODEX_HOME="$HOME/.codex" cdx login
CODEX_HOME="$HOME/.codex" cdx login status

看到 Logged in using ChatGPT 就算成功。auth.json 里的鉴权类型也会从 API Key 变成 ChatGPT OAuth tokens。检查这个文件时只看类型和字段是否存在,不要把内容打印出来。

坑:登录成功了,新会话还显示 API key

登录成功后,我打开一个新的 cdx 会话,/status 里依然显示 API key configured。

原因是 Codex 有一个本地后台 app-server,新开终端不一定会启动新的 server,它手里还拿着旧的鉴权状态。

先用不走后台 server 的独立进程确认配置本身没问题:

zsh
1
CODEX_HOME="$HOME/.codex" cdx --no-daemon

独立进程正常,就说明是后台 server 缓存了旧状态。重启它:

zsh
1
CODEX_HOME="$HOME/.codex" mise exec node@${CODEX_NODE} -- codex app-server daemon restart

重启会中断所有连在这个 server 上的会话,要在没有重要任务跑的时候做。我这次等了大约一分钟,旧进程退出,新 server 起来了。

再开 cdx,/status 里应该看到:

  • provider 仍然是 crs
  • Account 显示订阅账号和套餐
  • 能读到 Weekly limit

最后发一个不调工具的简单请求,返回 OK,说明官方端点实际可用。跨项目看历史:

zsh
1
cdx resume --all

注意:能看到历史列表,不代表每个旧会话都能恢复运行。我只验证了数据库记录完整,没有逐个恢复全部会话。

踩过和差点踩的坑

  1. 不要给 OAuth 实例随手加 forced_login_method = "api"。 我后来跑一个 DeepSeek 接入脚本时它加了这个字段,结果鉴权冲突,直接被登出。
  2. login status 只代表独立 CLI 进程的状态,不代表后台 server。 要结合新会话里的 /status、数据目录和后台进程一起判断。
  3. provider 名字说明不了请求发到哪、怎么计费。 我这里叫 crs,实际地址是官方端点,用的是订阅。
  4. 排查时不要打印完整配置、API Key 或 OAuth token。 备份目录也要收紧权限,里面有登录凭据和私人会话内容。
  5. 当前版本会把 preferred_auth_method 和 disable_response_storage 当成忽略项。 迁移能成功,靠的是 OAuth 凭据、provider 地址和 requires_openai_auth 这三样,不要以为写了那两个字段就能保证鉴权。

回滚原则

  • 要用中转,优先用已经隔离好的 cx,不要改回主实例。
  • 确实要回滚 cdx:先停掉相关工作,备份迁移后新增的数据,再只恢复必要的配置和鉴权文件。不要整个目录覆盖回去,那会把备份之后新产生的会话全部丢掉。

参考

「保留 crs 标识、替换官方地址」是我在当前版本上实际验证过的方案。Codex 升级以后,要重新检查一遍鉴权、请求地址和历史是否可见。