在 CI/CD 中维护 Codex 账号认证(高级)
使用 Codex 内置的刷新流程,让 auth.json 在受信任的 CI/CD runner 中持续可用
本指南说明如何在可信的 CI/CD 运行器上维持 ChatGPT 托管的 Codex 认证,而无须自行调用 OAuth token endpoint。
自动化任务应优先使用 API key 认证。只有当工作流确实需要以你的 Codex 账号身份运行时,才使用本指南中的方案。
整体流程如下:
- 在可信设备上运行一次
codex login,生成auth.json。 - 将该文件放到运行器上。
- 正常运行 Codex。
- 当会话过期时,由 Codex 自动刷新。
- 保存刷新后的
auth.json,供下一次运行使用。
这是一种面向企业及其他可信私有自动化环境的高级工作流。对于大多数 CI/CD 任务,API key 仍是推荐方案。
工作原理
Codex 本身已经能够刷新由 ChatGPT 托管的会话。
以当前的开源客户端为准:
- Codex 会从
auth.json加载本地认证缓存。 - 如果
last_refresh距今超过约 8 天,Codex 会先刷新令牌集,再继续运行。 - 刷新成功后,Codex 会把新令牌和新的
last_refresh写回auth.json。 - 如果请求收到
401,Codex 也有内建的刷新并重试流程。
因此,受支持的 CI/CD 策略不是“自行调用刷新 API”,而是“运行 Codex,并持久化更新后的 auth.json”。
适用条件
只有同时满足以下条件时,才使用本指南:
- 你需要 ChatGPT 托管的 Codex 认证,而不是 API key。
- 远程运行器无法执行
codex login。 - 运行器属于可信的私有基础设施。
- 你能够在多次运行之间保存刷新后的
auth.json。 - 一份
auth.json只由一台机器或一组串行执行的任务使用。
本指南适用于 Codex 管理的 ChatGPT 认证(auth_mode: "chatgpt")。
它不适用于:
- API key 认证。
- 由宿主应用管理外部 token 的集成(
auth_mode: "chatgptAuthTokens")。 - Codex 之外的通用 OAuth 客户端。
如果凭据保存在操作系统钥匙串中,请先改用文件存储。参见凭据存储。
仅初始化一次 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 密钥管理系统,或把文件复制到可信且可持久化的运行器。
推荐方案:使用自托管运行器的 GitHub Actions
最简单的全自动方案,是使用带持久化 CODEX_HOME 的自托管 GitHub Actions 运行器。
这一方案具有以下优势:
- 运行器可以在多次任务之间保留磁盘上的
auth.json。 - Codex 可以直接刷新原文件。
- 后续任务会自动使用刷新后的令牌。
- 原始 secret 只在初始化或重新写入凭据时需要。
关键在于:仅当 auth.json 不存在时才写入初始文件。如果每次运行都用原始 secret 覆盖该文件,就会丢掉 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 exec步骤中由 Codex 自动刷新。 - 将刷新后的文件保留在磁盘上,供下一次工作流运行使用。
当前开源客户端会在大约 8 天后把会话视为已过期,因此每周运行一次通常就足够。
临时运行器:恢复文件、运行 Codex,再持久化更新后的文件
如果使用 GitHub 托管运行器、GitLab 共享运行器或其他临时环境,每个任务结束后,运行器的文件系统都会被清除。此时需要完成一次完整的往返流程:
- 从安全存储中恢复当前的
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 在本次运行中生成的刷新后文件,而不是最初用于初始化的原始文件。
不需要单独的刷新命令
任何一次正常的 Codex 运行都可以刷新会话。
因此有两种合适的做法:
- 让现有的 CI/CD Codex 任务自然刷新该文件。
- 如果实际任务运行得不够频繁,可以增加一个轻量的定时维护任务,如上面的 GitHub Actions 示例。
会话达到过期条件后,第一次运行 Codex 时就会刷新 auth.json。
关键运行规则
- 每台运行器或每组串行工作流使用一份独立的
auth.json。 - 不要让并发任务或多台机器共享同一文件。
- 不要在每次运行时用原始文件覆盖持久化运行器上已经刷新的文件。
- 不要把
auth.json存入仓库、日志或公开的产物存储。 - 如果内建刷新不再有效,请在可信设备上重新生成认证文件。
刷新失效时的处理方法
该流程可以减少人工操作,但不能保证同一会话永久有效。
出现以下情况时,请用新的 auth.json 重新初始化运行器:
- Codex 开始返回
401,并且运行器无法继续刷新。 - refresh token 已被撤销或过期。
- 另一台机器或并发任务率先轮换了令牌。
- 安全存储的往返流程失败,恢复了旧文件。
重新初始化:
- 在可信设备上运行
codex login。 - 替换 CI/CD 中保存的
auth.json。 - 让下一个运行器任务继续使用 Codex 的内建刷新流程。
验证运行器是否持续维护会话
检查运行器是否仍保存着托管认证所需的令牌,以及 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"对于持久化运行器,同一文件应在多次运行之间始终存在。对于临时运行器,请确认回写步骤保存的是上一次任务生成的更新后文件。
源码参考
如需在开源客户端中验证上述行为:
codex-rs/core/src/auth.rs涵盖过期 token 检测、自动刷新、收到 401 后的刷新恢复,以及刷新后 token 的持久化。codex-rs/core/src/auth/storage.rs涵盖基于文件的auth.json存储。