Codex 多账号切换不再折腾:OAuth 配对与 Auth 迁移实践

本文最后更新于 2026年9月5日 凌晨

最近我一直在测试各种 Agent 客户端产品,经常要比较同一套模型在不同客户端里的登录、调用和工作流体验。偏偏手上的账号也不止一个:一个是自己付费订阅的 ChatGPT Plus,另一个则通过面向开源维护者的 Codex for Open Source 计划获得了 ChatGPT Pro 20x 权益。

账号多本来是件好事,真正测试起来却很折腾:日常工作想留在 Plus 账号,遇到开源项目又会切到 Pro;每次退出再登录既慢,也很容易弄混当前账号。

手动备份和替换 ~/.codex/auth.json 当然可以,但文件名很快就会变成 auth-old.jsonauth-new.jsonauth-final.json。更麻烦的是,登录凭据在使用过程中可能自动刷新,旧备份并不一定还是最新状态

于是我做了 Codex Auth Switch:一个基于 Tauri、React 和 Rust 的纯本地桌面工具。它最初只负责保存和切换账号,后来又加入 OAuth 配对、一次性 Auth 迁移、本机 Token 统计、模型提供方归类、订阅额度巡检和只读环境体检。

Codex Auth Switch 账号管理界面

本文已按 v1.1.2 更新。截图和动图也已同步到该版本,均使用项目内置预览数据,并开启私密模式。账号、用量、验证码和迁移二维码均为演示内容,不包含真实认证信息;动图用于展示界面操作步骤,不代表实际网络耗时。

简单概括,Codex Auth Switch 解决的是三个不同场景:切换留在本机,添加交给 OAuth,换机才使用一次性迁移。

快速开始

下载安装

Codex Auth Switch 提供 macOS、Windows 和 Linux 安装包,可以从 GitHub Releases 下载;如果 GitHub 速度不理想,也可以使用 CNB Release 镜像。GitHub 会先完成发布,CNB 镜像随后自动同步,刚发布时可能稍有延迟。本文对应的版本为 1.1.2,已安装用户也可在“设置 → 软件更新”中检查升级。

系统 架构 推荐安装包
macOS Apple Silicon macOS_arm64.dmg
macOS Intel macOS_x64.dmg
Windows x64 Windows_x64-setup.exe,也可选择 .msi
Linux x64 .AppImage.deb.rpm

macOS 下载后打开 DMG,将应用拖入“应用程序”目录。安装包目前使用 ad-hoc 签名,首次启动如果被系统拦截,可以前往“系统设置 → 隐私与安全性”确认打开。Windows 推荐使用 setup.exe;Linux 则按发行版选择 DEB 或 RPM,不想安装时可以直接运行 AppImage。Release 中的 .app.tar.gz.siglatest.json 是应用内更新使用的文件,手动安装不需要下载。

配置与操作

账号保存、切换和在线订阅额度查询需要 Codex 使用文件凭据。安装完成后,可以在应用的 “Codex 配置 → 凭据存储” 中选择文件模式,也可以手动编辑 CODEX_HOME/config.toml,默认是 ~/.codex/config.toml,加入:

1
cli_auth_credentials_store = "file"

只查看本地 Token 用量,不需要切换凭据模式。 1.1.2 已把本机会话统计与凭据存储模式解耦,fileautokeyring 都可以读取用量;账号管理仍只处理文件模式下的 ChatGPT 登录,不会把 API Key 登录当作订阅账号。

配置页还可以调整推理强度、推理摘要、回答详细度、联网搜索和 1M 上下文预设。选择“默认”会移除对应配置字段,让 Codex 使用默认行为;这些只是本机配置,实际支持情况仍取决于所用模型和 Codex 版本。

Codex 配置:凭据存储与上下文设置

需要管理账号时,按照下面的顺序操作:

  1. 保存当前账号:确认 Codex 已经通过 ChatGPT 订阅登录,打开 Codex Auth Switch,为当前登录设置名称并保存;
  2. 添加其他账号:选择“登录新账号”,设置本机名称,再到可信浏览器中输入配对码并完成授权;
  3. 日常切换账号:在本机账号库中选择目标账号,点击切换。Codex 下一次请求会读取新的 auth.json
  4. 查看本机用量:进入 Token 用量页,查看今天、近 7 天和近 30 天统计、14 天趋势、输入输出构成、账号归属与模型提供方拆分;
  5. 巡检订阅额度:进入订阅额度页,比较已保存账号的额度窗口、恢复时间线、可用完整重置次数与最早过期时间;支持刷新全部账号,也可以在卡片上单独刷新;
  6. 检查本机环境:在设置页运行只读体检,检查文件凭据配置、认证结构、文件权限、账号库一致性、切换历史与原子写残留;
  7. 管理用量缓存:在“设置 → 用量与额度”查看缓存占用,需要时点击“清理缓存”;
  8. 换机时迁移:只有旧设备准备停止使用该账号时,才生成一次性 Auth 迁移内容;两台设备需要长期使用时,请选择 OAuth 配对。

这样配置一次后,日常使用基本只需要“打开应用 → 选择账号 → 切换”。只有更换设备时,才需要使用一次性 Auth 迁移。

使用边界: Codex Auth Switch 只面向同一用户管理自己有权使用的账号,以及本人控制的可信设备。OpenAI 的账号共享政策允许本人在多个设备上使用自己的账号,但不允许把账号交给其他人;使用条款同样禁止共享凭据,以及规避用量限制或保护措施。本工具不会合并订阅额度或改变服务端限制,请勿用于出租、转售、共享账号或绕过限额。Codex 的登录缓存与 Device Code 说明以官方认证文档为准,条款更新时也应以官方最新版本为准。是否符合条款最终取决于实际使用方式;这里描述的是项目的设计边界,不构成法律意见。项目与 OpenAI 无隶属、赞助或背书关系,Device OAuth、令牌刷新和订阅用量查询中的具体线协议属于兼容性实现,并不是官方保证稳定的公开 API。

思路来源

这个想法最直接的灵感,来自 Jason Young 在 X 上分享的 使用 CC Switch 在两个 Codex 官方账号之间快速切换。帖子通过分别保存两份官方账号配置来减少重复登录,并处理切换后的凭据更新,让我确认:“多账号状态如何保持最新”并不是个例。

Codex Auth Switch 没有沿用通用供应商切换的路线,而是只聚焦 Codex 的本地文件凭据。在实际开发和使用中,我又把问题继续拆开:同一台电脑上的账号切换、自己的另一台设备独立登录,以及换机时的一次性交接,本质上是三条不同的流程。这也成为后续 OAuth 配对与 Auth 迁移功能的设计起点。

使用场景

最开始我把“多账号”理解成保存几份 Auth,然后在需要时替换当前文件。真正使用以后才发现,账号切换、给自己的另一台设备添加账号、把登录从旧设备搬到新设备,其实是三件不同的事

场景 推荐方式 适合做什么
同一台电脑切换账号 本机账号库 保存当前登录,之后一键切换
给自己的另一台设备添加账号 OAuth 配对 让新设备独立完成登录,适合长期使用
从旧设备搬到新设备 一次性 Auth 迁移 把登录交给接收端,发送端随后停止使用

选择方式时,可以先判断账号准备在哪里使用:

flowchart LR
    Start(["选择账号使用方式"])
    SameDevice{"只在同一台电脑<br/>切换多个账号?"}
    LongTerm{"自己的另一台设备是否需要<br/>长期独立使用?"}
    ReplaceDevice{"是否属于换机,且旧设备<br/>准备停止使用该账号?"}

    Local["本机账号库<br/>适合日常切换"]
    OAuth["OAuth 配对<br/>适合长期添加设备"]
    CAS3["一次性 Auth 迁移<br/>只用于换机交接"]

    LocalSteps["① 保存并命名当前登录<br/>② 切换前同步最新凭据<br/>③ 从账号库一键切换"]
    OAuthSteps["① 新设备发起配对<br/>② 同一用户在浏览器授权<br/>③ 新设备独立保存登录"]
    CAS3Steps["① 停止发送端 Codex 会话<br/>② 刷新并生成一次性 CAS3<br/>③ 接收端导入并接管凭据"]

    Start --> SameDevice
    SameDevice -->|"是"| Local
    SameDevice -->|"否"| LongTerm
    LongTerm -->|"是"| OAuth
    LongTerm -->|"否"| ReplaceDevice
    ReplaceDevice -->|"是"| CAS3
    ReplaceDevice -->|"否,两端仍需使用"| OAuth

    Local --> LocalSteps
    OAuth --> OAuthSteps
    CAS3 --> CAS3Steps

    classDef start fill:#fff7ed,stroke:#f97316,stroke-width:3px,color:#7c2d12
    classDef decision fill:#fffbeb,stroke:#d97706,stroke-width:2px,color:#78350f
    classDef local fill:#eff6ff,stroke:#2563eb,stroke-width:3px,color:#1e3a8a
    classDef oauth fill:#f0fdf4,stroke:#16a34a,stroke-width:3px,color:#14532d
    classDef transfer fill:#fff1f2,stroke:#e11d48,stroke-width:3px,color:#881337
    classDef detail fill:#f8fafc,stroke:#94a3b8,stroke-width:1.5px,color:#334155

    class Start start
    class SameDevice,LongTerm,ReplaceDevice decision
    class Local local
    class OAuth oauth
    class CAS3 transfer
    class LocalSteps,OAuthSteps,CAS3Steps detail

    linkStyle 1,7 stroke:#2563eb,stroke-width:2px
    linkStyle 3,6,8 stroke:#16a34a,stroke-width:2px
    linkStyle 5,9 stroke:#e11d48,stroke-width:2px

单机切换账号

Codex Auth Switch 会识别当前 Codex ChatGPT 登录,在你选择保存、登录或导入账号时,把快照保存在应用自己的本地账号库中。切换时,它会先同步已保存账号可能已经轮换过的凭据,再校验目标账号,最后原子替换 CODEX_HOME 中的 auth.json。移除本机快照后,自动同步不会再把它重新加回来;移除快照也不会让当前 Codex 退出登录。

整个切换过程不代理 Codex 请求。替换完成后,Codex 在下一次请求时读取新的本地凭据,账号切换就生效了。

本机账号库与单账号切换入口

应用也会读取 Codex 会话中的 token_count 元数据,汇总今天、近 7 天和近 30 天的本机 Token 用量。这里的 Token 数字只是本机会话统计,并不等于 ChatGPT 订阅额度;历史会话也不一定能准确归属到某个账号。

Codex Auth Switch Token 用量与模型提供方归类

除了账号归属,当前版本还会读取每个会话记录的 model_provider,把近 30 天 Token 按模型提供方拆开。OpenAI 默认提供方与各个自定义提供方会分别统计;没有记录 model_provider 的会话则归入未识别。这个字段只表示请求使用的模型提供方,不能证明使用的是 ChatGPT 订阅还是 API Key,也不能据此判断最终计费方式。普通模式只显示配置中的服务主机,不保存 API Key 或完整地址。

按模型提供方拆分用量与账号归属

官方文档同样区分了 ChatGPT 订阅登录和 API Key 登录;Codex Auth Switch 只管理文件模式下的 ChatGPT 登录缓存,不会把 API Key 当作订阅账号保存。

本地用量与缓存

会话文件多起来以后,每次切到用量页都从头解析 JSONL,等待会越来越明显。所以在 1.1.2 中,我给扫描增加了本地增量缓存:未变更的文件直接复用统计,文件有追加时只解析新增的完整行;写到一半的尾行留到下一次读取,文件被截断或替换时则重新扫描。

缓存只是为了减少重复读取,不能让这个小工具一直积累磁盘占用。目前的规则是:

项目 处理方式
缓存位置 应用数据目录中的 usage-cache.v2.json.gz
容量上限 压缩后最多 8 MiB,超限时淘汰较旧文件的缓存
统计保留 只保留近 35 天的事件,页面仍展示今天、近 7 天和近 30 天的统计
自动清理 启动或访问缓存时,删除超过 7 天未更新的缓存和旧版缓存
手动清理 “设置 → 用量与额度 → 清理缓存”,同时可以查看占用

设置中查看缓存占用并手动清理

清理缓存不会删除账号、认证文件或 Codex 会话,下一次刷新按需重建。容量淘汰也不会从本次显示的总量中扣掉数据,只影响后续需要重新读取哪些文件。缓存保存的是文件校验信息、提供方标识、事件时间和 Token 计数,不保存提示词、回复正文或认证令牌

用量读取还可以独立于当前认证工作:即使采用 autokeyring,也可以查看本机会话统计。不过,账号归属依然依赖应用已经记录的切换历史;没有可靠历史的用量不能凭空判断属于哪个账号。

订阅额度巡检

本机 Token 和在线订阅额度是两条独立的数据流。打开 Token 页面只读取本机会话统计,不会访问在线额度接口;订阅额度页则按账号查询窗口状态,并根据返回数据展示最近恢复、完整重置次数与最早过期时间。

1.1.2 不再要求等整批账号查完才一起显示结果。点击顶部“刷新额度”后,哪个账号先完成,就先更新哪张卡片;只想重试某个账号时,点击对应卡片上的“刷新”即可。查询过程中保留已有数据,失败时显示错误与上次成功查询的时间,避免把旧数据误当成刚刚刷新的结果。

单账号刷新时保留已有额度数据

不同账号共享最多 2 个并发名额,同一个账号的查询串行执行,防止同时使用正在轮换的凭据。某个账号失败不会抹掉其他账号的结果,网络等待也不会占住账号切换所需的全局操作锁。在“设置 → 用量与额度”中还可以关闭“进入页面时自动刷新”,改为手动读取。

Codex Auth Switch 订阅额度巡检与恢复时间线

“额度补给路线”把当前账号、最高窗口使用率、最近恢复与完整重置集中在一条时间线上,下面仍保留每个账号的窗口明细,方便判断应该继续使用当前账号,还是等待窗口自然恢复。订阅数据优先通过本机 Codex App Server 读取;不可用时再降级到隔离的 ChatGPT HTTP 兼容实现。并非所有账号或来源都返回完整字段,订阅到期日也不是当前可查询的信息。具体端点与线协议不应视为 OpenAI 保证稳定的公开 API,变化时可能影响额度显示。

跨设备账号添加

如果想让另一台电脑长期使用某个账号,我更推荐 OAuth 配对,而不是把现有 Auth 发过去

新设备在应用内发起登录后,会显示浏览器地址和短期有效的一次性验证码。同一用户在可信浏览器中登录 ChatGPT、输入验证码并完成授权,新设备随后自动保存并切换到新账号。这个过程不需要导出发送端已经存在的 Auth,也不需要把 ChatGPT 密码交给应用

这套 Device Code 流程并不是 Codex Auth Switch 自创的协议,而是 Codex CLI 本身就在用的登录方式:当 CLI 运行在没有本地浏览器的环境(例如 SSH 远程服务器)时,同样会显示一个验证地址和一次性验证码,让用户在别处的浏览器完成授权。Codex Auth Switch 只是把这套 CLI 已经在用的登录能力,接入到桌面应用里,用来给同一账号添加新设备,而不是重新实现一套认证协议。

从实现上看,浏览器授权和应用轮询是同时发生的。前端只展示授权地址、一次性验证码和剩余时间;真正的状态查询、令牌交换、账号校验与写入都在 Rust 后端完成:

sequenceDiagram
    autonumber
    actor User as 用户
    participant App as Codex Auth Switch(新设备)
    participant Auth as OpenAI 认证服务(Codex CLI 同款接口)
    participant Browser as 可信浏览器
    participant Local as 本地账号库 / auth.json

    App->>Auth: 申请 Device Code
    Auth-->>App: device_auth_id、user_code、有效期、轮询间隔
    App-->>User: 显示授权地址与一次性验证码

    par 用户完成浏览器授权
        User->>Browser: 登录并输入一次性验证码
        Browser->>Auth: 确认授权
    and 应用等待授权结果
        loop 未授权且验证码未过期
            App->>Auth: 按 interval 查询状态
            Auth-->>App: pending
        end
    end

    Auth-->>App: authorization_code + code_verifier
    App->>Auth: 交换登录令牌
    Auth-->>App: 返回登录材料
    App->>App: 校验 ChatGPT 登录与账号一致性
    App->>Local: 保存账号并原子替换 auth.json
    App-->>User: 登录完成并切换

OAuth 添加账号的完整链路

OAuth 配对:命名账号并生成一次性验证码

OpenAI 认证文档将 Device Code 登录标记为 Beta。个人用户可能需要先在 ChatGPT 安全设置中启用,工作区账号则可能需要管理员开放相应权限。这也意味着 Device Code 的具体接口和字段是 Codex CLI 的内部实现细节,并非官方对外承诺稳定的公开 API,未来可能随 CLI 自身的调整而变化。

1.1.2 还补上了登录取消的边界处理:后端记录本次配对会话,避免重复轮询;取消登录后,即使之前的网络请求稍后返回授权结果,也不会再提交这个已取消的会话。网络等待不会一直占用账号切换的操作锁。

需要注意:配对码虽然不是密码,但在有效期内同样可以授权设备,因此只能在本人预期的可信设备上使用,不能提供给其他人。

旧设备迁移

有时并不是要让两台设备一起使用,而是换电脑,希望把登录从旧设备搬到新设备。这时可以使用一次性 Auth 迁移。

应用会先明确提示迁移的使用边界:停止发送端的 Codex 桌面端、CLI 和 IDE 扩展,确认不会继续切换到这个账号,再刷新并准备迁移内容。

生成迁移内容前的安全提醒

发送端会先要求停止使用该账号,然后强制刷新凭据,生成二维码和剪贴板共用的一份 CAS3 迁移内容。CAS3 不再携带 access token、账号 ID、账号名称和刷新时间,只保留接收端兑换所需的数据;接收端导入后会立即联网刷新、校验账号并重建完整 Auth,全部成功后才写入本地

一次性 Auth 迁移:安全确认并生成二维码

接收端既可以读取剪贴板中的迁移文本,也可以选择应用生成的二维码图片。无论选择哪种方式,原始令牌都只在 Rust 后端中兑换和校验,不会显示在界面或写入日志

接收端选择 Auth 导入方式

上图二维码是内置预览数据。真实迁移内容包含可登录凭据,只能导入一次,不要截图留存或交给不受信任的人。接收端迁移成功后,发送端不应继续使用同一账号;需要两台设备长期使用时,请改用 OAuth 配对。

设计与实现

凭据流转

Codex 使用 ChatGPT 订阅登录并启用文件凭据模式后,当前登录会保存在 CODEX_HOME/auth.json,默认位置是 ~/.codex/auth.json。Codex Auth Switch 不修改 Codex 本身,只管理这份当前凭据,以及应用数据目录中的本机账号库。

需要说明的是,本机账号库目前依赖文件系统权限,而非加密存储:macOS/Linux 上应用数据目录权限为 0700,账号库和临时认证文件为 0600;系统钥匙串(Keychain/Credential Manager)中的账号管理暂不在支持范围内,但本地用量统计可以在这些凭据模式下使用。也就是说,如果设备本身已经被其他高权限用户或恶意程序控制,文件权限无法提供额外保护——auth.json 和账号库都应当被当作与密码同等敏感的数据来对待。

一次账号切换可以拆成三个动作:先读取当前 auth.json,同步已保存账号可能已经轮换过的凭据;再校验目标账号快照并写入同目录临时文件;最后通过原子替换更新 auth.json。Codex 下一次发起请求时读取新文件,切换便自然生效。API Key 登录始终走另一套路径,不会被保存成 ChatGPT 订阅账号。

关键路径可以简化为下面这段 Rust。临时文件与目标文件必须位于同一目录,写完后先 sync_all,最后再替换正式文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use std::{fs, io::{self, Write}, path::Path};

fn atomic_write(path: &Path, contents: &[u8]) -> io::Result<()> {
let parent = path.parent().ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidInput, "missing parent directory")
})?;
let mut temporary = tempfile::Builder::new()
.prefix(".auth-")
.suffix(".tmp")
.tempfile_in(parent)?;

temporary.write_all(contents)?;
temporary.as_file().sync_all()?;
temporary.persist(path).map_err(|error| error.error)?;
#[cfg(unix)]
fs::File::open(parent)?.sync_all()?;
Ok(())
}

示例省略了目录权限和认证校验。1.1.2 的实际实现使用 tempfile 创建私有临时文件,通过 persist 原子替换目标;Windows 路径不会先把原文件移走,Unix 路径还会同步父目录。替换前写入失败时,目标文件保持原样。

另一个容易忽略的问题是切换历史:不能先记录“已经切到 B”,然后才去写 auth.json,否则写入失败后用量就可能归错账号。现在会先保存待完成记录,再替换认证,成功后才确认激活历史;如果中途退出,下次读取根据实际认证恢复历史,本地用量也复用这套只读恢复逻辑。

额度查询与凭据轮换的成功与否也需要分开处理。即使查询套餐或窗口失败,已经轮换成功的凭据仍然要及时保存,不能因为页面没有拿到额度数据,就继续保留旧令牌。

flowchart LR
    UI["React 前端<br/>脱敏账号摘要 / 聚合用量 / 体检状态"]
    Core["Rust 后端<br/>凭据校验 / 原子替换 / 迁移处理<br/>用量聚合 / 本机体检"]
    Vault[("accounts.v1.json<br/>本机账号库")]
    Auth[("CODEX_HOME/auth.json<br/>当前登录凭据")]
    Sessions[("Codex 会话文件<br/>统计元数据")]
    Cache[("本地用量缓存<br/>压缩 / 容量上限 / 定期清理")]
    Codex["Codex<br/>CLI / Desktop / IDE"]
    OAuth["OAuth 配对<br/>授权结果"]
    CAS3["CAS3 一次性迁移<br/>刷新并校验"]

    UI <-->|"Tauri 命令 / 脱敏结果"| Core
    OAuth --> Core
    CAS3 --> Core
    Core <-->|"保存账号快照"| Vault
    Core <-->|"同目录原子替换"| Auth
    Sessions -->|"增量扫描"| Core
    Core <-->|"可重建统计"| Cache
    Auth -->|"下一次请求读取"| Codex

    classDef ui fill:#fff7ed,stroke:#f97316,stroke-width:2px,color:#7c2d12
    classDef core fill:#eff6ff,stroke:#2563eb,stroke-width:2px,color:#1e3a8a
    classDef storage fill:#f8fafc,stroke:#64748b,stroke-width:2px,color:#334155
    classDef flow fill:#f0fdf4,stroke:#16a34a,stroke-width:2px,color:#14532d

    class UI ui
    class Core core
    class Vault,Auth,Sessions,Cache storage
    class OAuth,CAS3,Codex flow

CAS3 的编码边界

CAS3 是 Codex Auth Switch 自己定义的一次性迁移兼容格式,不是 OpenAI 官方协议。文本形式是 CAS3: 加上 Base64URL(zlib(JSON));二维码形式则使用 CAS3Q 前缀直接携带压缩后的字节。解压后的字段只有两个:

1
2
3
4
{
"d": "<id_token>",
"r": "<refresh_token>"
}

其中 d 用于在接收端确认账号身份,r 用于立即刷新并重建完整的 Codex Auth。CAS3 不携带 access_tokenaccount_id、本机账号名称或刷新时间;接收端只有在刷新成功、ID Token 校验通过且账号一致时,才会写入账号库和 auth.json。完整编解码逻辑可以在 auth_share.rs 中查看。

字段少并不意味着它可以公开:id_tokenrefresh_token 仍然属于认证材料,CAS3 内容必须像密码一样保护。格式版本与内部字段也可能随项目升级调整,不能把它当作稳定的第三方集成接口。

OAuth 配对与一次性迁移最终也会回到同一个本地文件,但过程不同。OAuth 由新设备发起 Device Code 流程,授权完成后在本机生成 Codex 可读取的登录缓存;CAS3 迁移只携带接收端兑换所需的数据,接收端必须先刷新令牌并校验账号一致性,全部成功后才写入账号库和 auth.json

原始令牌的校验、迁移编解码、二维码和剪贴板处理都留在 Rust 后端,React 前端不会拿到可复制的令牌文本,错误信息和日志也不会输出令牌。项目没有自建后端、遥测或分析服务,但这并不等于设备失陷后仍然安全:auth.json 本质上仍是登录凭据,应当像密码一样保护。

扩展功能

最早写原型时,我以为核心工作只是把几份 auth.json 保存起来,再提供一个切换按钮。真正开始处理凭据轮换、OAuth 和换机迁移后才发现,文件替换反而是最简单的一步,难的是让每个失败分支都不会破坏用户当前还能使用的登录

因此在 Rust 后端里,我给认证操作定了几条硬约束:

  • 切换前同步已保存账号可能已经轮换的凭据,目标账号校验失败时不改动现有 auth.json,也不把切换失败记为成功;
  • 新文件必须先在同目录完整写入,再通过原子替换生效,避免中途退出留下半份凭据;
  • OAuth 与 CAS3 保持为两条独立流程,迁移内容只有在刷新成功、账号一致性校验通过后才允许落盘;
  • 额度查询失败也要保存已轮换凭据,取消 OAuth 登录后不能再提交迟到的结果;
  • 原始令牌不进入 React 状态,也不能出现在日志或错误信息中;
  • 用量缓存必须有容量上限、保留期限和清理入口,清理范围只限可重建的缓存。

我选择 Tauri,也不是为了给脚本简单套一个界面。账号切换需要直接处理本地文件权限,迁移又涉及剪贴板、二维码和系统文件选择器,这些操作放在 Rust 中更容易收紧边界;React 的职责则是把当前账号、下一步会发生什么、失败后是否保持原状说明白。

后面加入的 Token 用量、模型提供方归类、独立订阅额度页、邮箱私密模式、亮暗主题和应用内更新,本质上都是围绕日常使用补齐的信息。设置页还提供了一次只读的本地环境体检:由 Rust 检查配置、认证文件、权限、账号库、切换历史与原子写残留,前端只接收检查状态和计数,不接收令牌、账号 ID 或文件内容。

Codex Auth Switch 本地环境体检

从开发者角度看,这个项目最重要的功能边界同样写在“没有做”的部分:不代理 Codex 请求,不保留或传递提示词和回复,不把账号同步到云端,也不把 API Key 与 ChatGPT 订阅登录混在一起。认证工具的功能可以继续增加,但每增加一条数据流,都应该先解释它为什么必须存在。

END

如果你也有多个 Codex ChatGPT 登录,希望 Codex Auth Switch 能帮你把手动备份和替换 auth.json 的过程收起来。账号切换应该足够顺手,但认证数据仍然值得被认真对待。

项目基于 Tauri + React + Rust 构建并完全开源,欢迎在 GitHub 上 Star、提 Issue 反馈问题,或者直接提交 PR 一起完善凭据管理和迁移流程。



Codex 多账号切换不再折腾:OAuth 配对与 Auth 迁移实践
https://www.mintimate.cn/2026/08/29/codexAuthSwitch/
作者
Mintimate
发布于
2026年8月29日
许可协议