在 CI/CD 中维护 Codex 账户身份验证(高级)
本指南介绍如何在受信任的 CI/CD runner 上保持 ChatGPT 管理的 Codex 身份验证正常工作,而无需自行调用 OAuth 令牌端点。
自动化身份验证的正确方式是使用 API key。仅当你明确需要以自己的 Codex 账户运行工作流时,才使用本指南。
模式如下:
- 在受信任的计算机上使用
codex login创建一次auth.json。 - 将该文件放到 runner 上。
- 正常运行 Codex。
- 当会话变得过期时,让 Codex 刷新会话。
- 保留刷新的
auth.json,供下一次运行使用。
这是面向企业和其他受信任私有自动化环境的高级工作流。对于大多数 CI/CD 作业,仍建议使用 API key。
请将 ~/.codex/auth.json 视同密码处理:其中包含访问令牌。不要将其提交到代码库、粘贴到工单中,或分享到聊天中。不要将此工作流用于公共代码库或开源代码库。
Codex 已经知道如何刷新 ChatGPT 管理的会话。
截至当前的开源客户端:
- Codex 从
auth.json加载本地身份验证缓存 - 如果
last_refresh距今已超过约 8 天,Codex 会在继续运行前刷新令牌包 - 刷新成功后,Codex 会将新令牌和新的
last_refresh写回auth.json - 如果请求返回
401,Codex 也有内置的刷新并重试路径
这意味着,受支持的 CI/CD 策略不是“自行调用刷新 API”,而是“运行 Codex 并持久化更新后的 auth.json”。
何时使用本指南
Section titled “何时使用本指南”仅当以下条件全部满足时,才使用本指南:
- 你需要 ChatGPT 管理的 Codex 身份验证,而不是 API key
codex login无法在远程 runner 上运行- runner 是受信任的私有基础设施
- 你可以在多次运行之间保留刷新的
auth.json - 每个
auth.json副本只会由一台计算机或串行作业流使用
本指南适用于 Codex 管理的 ChatGPT 身份验证(auth_mode: "chatgpt")。
本指南不适用于:
- API key 身份验证
- 外部令牌主机集成(
auth_mode: "chatgptAuthTokens") - Codex 之外的通用 OAuth 客户端
如果你的凭据存储在操作系统密钥环中,请先切换为文件存储。请参阅凭据存储。
初始化一次 auth.json
Section titled “初始化一次 auth.json”在可以进行浏览器登录的受信任计算机上:
- 将 Codex 配置为在文件中存储凭据:
cli_auth_credentials_store = "file"- 运行:
codex login- 验证文件内容是否为 ChatGPT 管理的身份验证:
AUTH_FILE="${CODEX_HOME:-$HOME/.codex}/auth.json"
jq '{ auth_mode, has_tokens: (.tokens != null), has_refresh_token: ((.tokens.refresh_token // "") != ""), last_refresh}' "$AUTH_FILE"仅当以下条件满足时,才继续:
auth_mode为"chatgpt"has_refresh_token为true
然后,将 auth.json 的内容放入 CI/CD 密钥管理器,或将其复制到受信任的持久化 runner。
推荐模式:在自托管 runner 上使用 GitHub Actions
Section titled “推荐模式:在自托管 runner 上使用 GitHub Actions”最简单的全自动设置是使用带有持久化 CODEX_HOME 的自托管 GitHub Actions runner。
这种模式运行良好的原因:
- runner 可以在不同作业之间将
auth.json保留在磁盘上 - Codex 可以直接更新该文件
- 后续作业会自动获取刷新的令牌
- 你只需在引导或重新初始化时使用原始密钥
关键在于,仅当 auth.json 不存在时才进行初始化。如果每次运行都使用原始密钥重写文件,就会丢弃 Codex 刚刚写入的刷新令牌。
计划任务工作流示例:
name: Keep Codex auth fresh
on: schedule: - cron: "0 9 * * 1" workflow_dispatch:
jobs: keep-codex-auth-fresh: runs-on: self-hosted steps: - name: Bootstrap auth.json if needed shell: bash env: CODEX_AUTH_JSON: ${{ secrets.CODEX_AUTH_JSON }} run: | export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}" mkdir -p "$CODEX_HOME" chmod 700 "$CODEX_HOME"
if [ ! -f "$CODEX_HOME/auth.json" ]; then printf '%s' "$CODEX_AUTH_JSON" > "$CODEX_HOME/auth.json" chmod 600 "$CODEX_HOME/auth.json" fi
- name: Run Codex shell: bash run: | codex exec --json "Reply with the single word OK." >/dev/null其工作方式如下:
- 第一次运行时初始化
auth.json - 后续运行复用同一个文件
- 缓存的会话达到过期条件后,Codex 会在正常的
codex exec步骤中刷新会话 - 刷新后的文件会保留在磁盘上,供下一次工作流运行使用
通常每周运行一次就足够,因为在当前的开源客户端中,Codex 会在大约 8 天后将会话视为过期。
临时 runner:恢复、运行 Codex,并持久化更新后的文件
Section titled “临时 runner:恢复、运行 Codex,并持久化更新后的文件”如果你使用 GitHub 托管的 runner、GitLab 共享 runner 或任何其他临时环境,runner 的文件系统会在每个作业结束后消失。在这种设置下,你需要完成一次往返流程:
- 从安全存储中恢复当前的
auth.json - 运行 Codex
- 将更新后的
auth.json写回安全存储
通用的 GitHub Actions 结构:
name: Run Codex with managed auth
on: workflow_dispatch:
jobs: codex-job: runs-on: ubuntu-latest steps: - name: Restore auth.json shell: bash run: | export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}" mkdir -p "$CODEX_HOME" chmod 700 "$CODEX_HOME"
# Replace this with your secret manager or secure storage command. my-secret-cli read codex-auth-json > "$CODEX_HOME/auth.json" chmod 600 "$CODEX_HOME/auth.json"
- name: Run Codex shell: bash run: | codex exec --json "summarize the failing tests"
- name: Persist refreshed auth.json if: always() shell: bash run: | # Replace this with your secret manager or secure storage command. my-secret-cli write codex-auth-json < "$CODEX_HOME/auth.json"关键要求是,写回步骤必须存储 Codex 在本次运行中生成的刷新后文件,而不是原始初始化文件。
无需单独的刷新命令
Section titled “无需单独的刷新命令”任何正常的 Codex 运行都可以刷新会话。
这意味着你有两种可行的选择:
- 让现有的 CI/CD Codex 作业自然地刷新文件
- 如果实际作业运行得不够频繁,则添加一个轻量级的计划维护作业,例如上面的 GitHub Actions 示例
会话变得过期后的第一次 Codex 运行会刷新 auth.json。
重要的运维规则
Section titled “重要的运维规则”- 每个 runner 或每个串行工作流流使用一个
auth.json。 - 不要在并发作业或多台计算机之间共享同一个文件。
- 不要在每次运行时都使用原始初始化文件覆盖持久化 runner 上已刷新的文件。
- 不要将
auth.json存储在代码库、日志或公共工件存储中。 - 如果内置刷新停止工作,请从受信任的计算机重新初始化。
刷新停止工作时的处理方式
Section titled “刷新停止工作时的处理方式”此流程可以减少手动操作,但无法保证同一个会话永久持续。
如果出现以下情况,请使用新的 auth.json 重新初始化 runner:
- Codex 开始返回
401,且 runner 无法再刷新 - 刷新令牌被撤销或已过期
- 另一台计算机或并发作业先轮换了令牌
- 安全存储往返失败,恢复了旧文件
重新初始化的步骤:
- 在受信任的计算机上运行
codex login。 - 替换存储的 CI/CD
auth.json副本。 - 让下一次 runner 作业继续使用 Codex 的内置刷新流程。
验证 runner 是否在维护会话
Section titled “验证 runner 是否在维护会话”检查 runner 是否仍然具有由 ChatGPT 管理的身份验证令牌,以及是否存在 last_refresh:
AUTH_FILE="${CODEX_HOME:-$HOME/.codex}/auth.json"
jq '{ auth_mode, last_refresh, has_access_token: ((.tokens.access_token // "") != ""), has_id_token: ((.tokens.id_token // "") != ""), has_refresh_token: ((.tokens.refresh_token // "") != "")}' "$AUTH_FILE"如果 runner 是持久化的,你应该会看到同一个文件在多次运行之间持续存在。如果 runner 是临时的,请确认写回步骤存储的是上一个作业生成的更新后文件。
如果你希望在开源客户端中验证此行为:
codex-rs/core/src/auth.rs涵盖过期令牌检测、自动刷新、401时的刷新并重试,以及刷新后令牌的持久化codex-rs/core/src/auth/storage.rs涵盖基于文件的auth.json存储