OpenAI Codex CLI 认证、模型额度与 Remote Control 排障报告

本文为公开脱敏版。文中的主机名、账号、会话 ID、设备码、配对码、具体服务器路径及精确时间均使用通用变量或占位符表示。

一、环境与最终状态

测试环境:

  • 远程 Linux 服务器
  • OpenAI Codex CLI standalone 安装
  • 使用 ChatGPT 账号通过设备码登录
  • 使用 Remote Control 连接远程设备

本文统一使用以下路径变量:

export CODEX_HOME="$HOME/.codex"
export CODEX_CLEAN_HOME="$HOME/.codex-clean-test"

最终状态:

Codex 主认证:正常
access token:正常
refresh token:正常
Codex Spark 模型:可正常调用
默认高能力模型:因额度耗尽暂时不可用
codex_apps:已临时关闭
standalone 安装:正常
Remote Control:启动成功

最终推荐配置:

model = "gpt-5.3-codex-spark"
cli_auth_credentials_store = "file"

[features]
apps = false

如需信任特定项目目录,可以另外添加:

[projects."/path/to/project"]
trust_level = "trusted"

二、问题总览

本次连续遇到了四类不同问题:

  1. codex_apps 启动时返回 HTTP 401 token_revoked
  2. Codex 主登录的 refresh token 被撤销
  3. 默认模型额度耗尽
  4. Remote Control 找不到 standalone Codex 安装

这些问题互相独立,不能只通过重复登录一次性解决。


三、问题一:codex_apps 返回 HTTP 401

3.1 错误表现

Codex 启动时出现:

MCP client for `codex_apps` failed to start

HTTP 401

Encountered invalidated oauth token for user
code: token_revoked

同时可能出现:

MCP startup incomplete (failed: codex_apps)

3.2 错误含义

失败的是 Codex 内置的 Apps/Connectors 集成层,而不一定是主模型认证。

codex_apps 主要负责接入外部应用或托管连接器,例如:

  • Google Drive
  • Slack
  • GitHub 连接器
  • 其他 ChatGPT Apps

下面的命令显示没有自定义 MCP:

codex mcp list

可能输出:

No MCP servers configured yet.

这与 codex_apps 报错并不矛盾,因为 codex_apps 是内置连接器,不一定出现在手动配置的 MCP 列表中。


四、为什么删除 auth.json 后仍可能报错

初步尝试通常包括:

codex logout
codex login status

rm -f "$HOME/.codex/auth.json"
rm -f "$HOME/.codex/oauth.json"

codex login

但删除文件后,codex_apps 仍可能继续返回:

HTTP 401
token_revoked

原因可能包括:

  • 实际使用的 CODEX_HOME 不是 $HOME/.codex
  • 凭证存储在系统 keyring 中
  • 主认证与 Apps OAuth 是两套认证
  • 其他 Codex 进程仍持有旧 token
  • 另一台设备或 IDE 扩展触发了 token 轮换
  • 服务端已经撤销旧 refresh token
  • 工作区切换导致旧授权失效

因此,删除默认目录中的 JSON 文件,不一定代表所有认证状态都已清除。


五、创建隔离的干净认证环境

为了排除旧缓存和系统 keyring,可以创建一个全新的 CODEX_HOME

codex logout 2>/dev/null || true

unset OPENAI_API_KEY
unset CODEX_ACCESS_TOKEN
unset CODEX_API_KEY

export CODEX_CLEAN_HOME="$HOME/.codex-clean-test"
export CODEX_HOME="$CODEX_CLEAN_HOME"

rm -rf "$CODEX_HOME"
install -d -m 700 "$CODEX_HOME"

printf '%s\n' \
  'cli_auth_credentials_store = "file"' \
  > "$CODEX_HOME/config.toml"

chmod 600 "$CODEX_HOME/config.toml"

codex login --device-auth

设备码登录时:

  1. 打开终端显示的官方登录页面
  2. 输入一次性设备码
  3. 登录正确的 ChatGPT 账号
  4. 选择正确的个人或团队工作区
  5. 登录完成前,不要在其他终端执行 codex logout

登录成功后会显示:

Successfully logged in

六、为什么“刚登录能用”,随后又提示 refresh token revoked

可能出现以下现象:

  1. 设备码登录成功
  2. Codex 界面可以启动
  3. 模型菜单可以切换
  4. 真正发送模型请求时出现:
Your access token could not be refreshed because your refresh token was revoked.

这两件事并不矛盾。

Codex 登录凭证通常包括:

access_token
refresh_token
id_token

刚登录后,新的 access_token 可能暂时有效,因此 Codex 可以:

  • 启动界面
  • 读取配置
  • 显示模型列表
  • 执行部分本地操作

当 access token 需要刷新时,Codex 会使用 refresh_token

如果 refresh token 已被撤销或轮换,就会在这时暴露错误。

因此:

codex login status

只能说明本地存在登录信息,不代表完整认证链路一定正常。

必须通过真实模型请求验证。


七、重新生成主认证

首先关闭可能持有旧凭证的进程:

pkill -TERM -x codex 2>/dev/null || true
pkill -TERM -f 'codex.*app-server' 2>/dev/null || true

sleep 2

pgrep -af codex || true

固定认证目录并清除环境变量:

export CODEX_HOME="$HOME/.codex-clean-test"

unset OPENAI_API_KEY
unset CODEX_ACCESS_TOKEN
unset CODEX_API_KEY

备份旧认证:

mkdir -p "$CODEX_HOME/auth-backup"

if [ -f "$CODEX_HOME/auth.json" ]; then
  cp -a "$CODEX_HOME/auth.json" \
    "$CODEX_HOME/auth-backup/auth.json.$(date +%Y%m%d-%H%M%S).bak"
fi

删除失效凭证:

rm -f "$CODEX_HOME/auth.json"
rm -f "$CODEX_HOME/oauth.json"

重新登录:

codex login --device-auth

八、关闭异常的 codex_apps

如果主模型功能正常,但 codex_apps 仍然持续报 token_revoked,可以临时关闭 Apps 集成。

写入配置:

printf '%s\n' \
  'cli_auth_credentials_store = "file"' \
  '' \
  '[features]' \
  'apps = false' \
  > "$CODEX_HOME/config.toml"

chmod 600 "$CODEX_HOME/config.toml"

cat "$CODEX_HOME/config.toml"

正确内容:

cli_auth_credentials_store = "file"

[features]
apps = false

关闭 apps 不会影响:

  • 本地代码读取
  • 修改文件
  • Shell 命令
  • Git
  • 编译和测试
  • /review
  • 普通模型调用
  • Remote Control

关闭后暂时不能使用:

  • ChatGPT Apps
  • 外部 Connectors
  • 依赖 codex_apps 的托管 MCP 工具

九、安全检查认证文件

检查登录状态:

codex login status
ls -l "$CODEX_HOME/auth.json"

正常应看到:

Logged in using ChatGPT

并且 auth.json 权限应类似:

-rw------- 

可以使用下面的 Python 脚本,只检查 token 字段是否存在,不显示真实内容:

python3 - <<'PY'
import json
import os

codex_home = os.environ.get(
    "CODEX_HOME",
    os.path.expanduser("~/.codex"),
)

path = os.path.join(codex_home, "auth.json")

with open(path, "r", encoding="utf-8") as f:
    auth = json.load(f)

tokens = auth.get("tokens") or {}

print("auth_file:", path)
print("auth_mode:", auth.get("auth_mode"))
print("has_access_token:", bool(tokens.get("access_token")))
print("has_refresh_token:", bool(tokens.get("refresh_token")))
print("has_id_token:", bool(tokens.get("id_token")))
print("last_refresh_exists:", bool(auth.get("last_refresh")))
PY

正常结果:

auth_mode: chatgpt
has_access_token: True
has_refresh_token: True
has_id_token: True
last_refresh_exists: True

不要公开执行或粘贴:

cat "$CODEX_HOME/auth.json"

也不要公开:

  • access token
  • refresh token
  • id token
  • Cookie
  • Authorization header
  • 完整 auth.json

十、使用真实模型请求验证认证

不要只依赖:

codex login status

应当执行真实请求:

env -u OPENAI_API_KEY \
    -u CODEX_ACCESS_TOKEN \
    -u CODEX_API_KEY \
    CODEX_HOME="$CODEX_HOME" \
    codex exec \
    --skip-git-repo-check \
    --ephemeral \
    'Reply with exactly OK and nothing else.'

可能出现三类结果。

10.1 返回 OK

说明以下链路正常:

auth.json
→ access token
→ Codex 服务
→ 模型响应

10.2 返回 refresh token was revoked

说明主认证仍然失效,需要重新停止所有 Codex 进程并执行设备码登录。

10.3 返回 You've hit your usage limit

说明认证已经成功,只是当前模型额度耗尽。

额度错误不是认证错误,不需要继续反复退出登录。


十一、默认模型额度耗尽后的处理

默认模型可能返回:

You've hit your usage limit.
Try again at <RESET_TIME>.

这说明:

账号认证正常
当前模型额度耗尽

可以切换到仍有可用额度的 Spark 模型:

env -u OPENAI_API_KEY \
    -u CODEX_ACCESS_TOKEN \
    -u CODEX_API_KEY \
    CODEX_HOME="$CODEX_HOME" \
    codex exec \
    -m gpt-5.3-codex-spark \
    --skip-git-repo-check \
    --ephemeral \
    'Reply with exactly OK and nothing else.'

返回:

OK

即表示 Spark 可用。

交互式启动:

codex -m gpt-5.3-codex-spark

设为默认模型:

model = "gpt-5.3-codex-spark"

完整配置示例:

model = "gpt-5.3-codex-spark"
cli_auth_credentials_store = "file"

[features]
apps = false

十二、不要移动整个 $HOME/.codex

曾经为了隔离旧状态,移动了整个默认目录:

mv "$HOME/.codex" "$HOME/.codex-broken-backup"

随后执行:

codex

可能出现:

No such file or directory

原因是 standalone 安装方式下,$HOME/.codex 不只是认证目录,还可能包含:

$HOME/.codex/packages/standalone/current/codex

$HOME/.local/bin/codex 可能依赖这个实际程序路径。

所以移动整个 $HOME/.codex,可能同时移走:

  • Codex standalone 程序
  • app-server
  • Remote Control 所需组件
  • 版本元数据
  • 安装器管理文件

恢复方法:

mv "$HOME/.codex-broken-backup" "$HOME/.codex"
hash -r

以后需要重置认证时,只处理:

$CODEX_HOME/auth.json
$CODEX_HOME/oauth.json

不要直接删除或移动整个 $HOME/.codex


十三、Remote Control 找不到 standalone 安装

在使用隔离目录时:

export CODEX_HOME="$HOME/.codex-clean-test"

执行:

codex remote-control start

可能报错:

managed standalone Codex install not found at
$CODEX_HOME/packages/standalone/current/codex

原因是干净目录中只有:

auth.json
config.toml

但 Remote Control 要求当前 CODEX_HOME 中同时存在:

packages/standalone/current/codex

普通 Codex 命令可以通过 PATH 中的入口运行,但 Remote Control daemon 要求使用安装器管理的固定 standalone 路径。


十四、将有效认证迁移回正式目录

首先确认正式目录中存在 standalone:

export CODEX_HOME="$HOME/.codex"

ls -l "$CODEX_HOME/packages/standalone/current/codex"

停止相关进程:

pkill -TERM -x codex 2>/dev/null || true
pkill -TERM -f 'codex.*app-server' 2>/dev/null || true
sleep 2

备份正式目录中的旧认证:

mkdir -p "$HOME/.codex/auth-backup"

if [ -f "$HOME/.codex/auth.json" ]; then
  mv "$HOME/.codex/auth.json" \
    "$HOME/.codex/auth-backup/auth.json.old.$(date +%Y%m%d-%H%M%S)"
fi

if [ -f "$HOME/.codex/config.toml" ]; then
  cp -a "$HOME/.codex/config.toml" \
    "$HOME/.codex/auth-backup/config.toml.old.$(date +%Y%m%d-%H%M%S)"
fi

复制已验证成功的认证和配置:

install -m 600 \
  "$HOME/.codex-clean-test/auth.json" \
  "$HOME/.codex/auth.json"

install -m 600 \
  "$HOME/.codex-clean-test/config.toml" \
  "$HOME/.codex/config.toml"

统一使用正式目录:

export CODEX_HOME="$HOME/.codex"

unset OPENAI_API_KEY
unset CODEX_ACCESS_TOKEN
unset CODEX_API_KEY

hash -r

验证:

echo "$CODEX_HOME"
codex login status
ls -l "$CODEX_HOME/packages/standalone/current/codex"

十五、迁移后验证 Spark

env -u OPENAI_API_KEY \
    -u CODEX_ACCESS_TOKEN \
    -u CODEX_API_KEY \
    CODEX_HOME="$HOME/.codex" \
    codex exec \
    -m gpt-5.3-codex-spark \
    --skip-git-repo-check \
    --ephemeral \
    'Reply with exactly OK and nothing else.'

返回:

OK

说明有效认证已经成功迁移到正式 CODEX_HOME


十六、启动 Remote Control

统一目录后执行:

export CODEX_HOME="$HOME/.codex"

codex remote-control stop 2>/dev/null || true
codex remote-control start
codex remote-control pair

启动成功时会出现类似:

Starting app-server daemon with remote control enabled...

This machine is available for remote control as <SERVER_HOSTNAME>.

Daemon used app-server:
  path: <CODEX_HOME>/packages/standalone/current/codex
  version: <CODEX_VERSION>

Pairing code: <PAIRING_CODE>

不要公开真实配对码。

如果配对码曾被发到聊天、论坛、截图或日志中,应重新生成:

codex remote-control pair

只在自己的受信任设备中输入新配对码。


十七、永久固定 CODEX_HOME

将正式目录写入 Shell 配置:

grep -qxF 'export CODEX_HOME="$HOME/.codex"' "$HOME/.bashrc" ||
  echo 'export CODEX_HOME="$HOME/.codex"' >> "$HOME/.bashrc"

source "$HOME/.bashrc"

验证:

echo "$CODEX_HOME"

应输出:

<用户主目录>/.codex

检查最终配置:

cat "$CODEX_HOME/config.toml"

推荐配置:

model = "gpt-5.3-codex-spark"
cli_auth_credentials_store = "file"

[features]
apps = false

十八、可直接复用的标准恢复流程

18.1 固定正式目录

export CODEX_HOME="$HOME/.codex"

18.2 排除环境变量干扰

unset OPENAI_API_KEY
unset CODEX_ACCESS_TOKEN
unset CODEX_API_KEY

18.3 停止旧进程

pkill -TERM -x codex 2>/dev/null || true
pkill -TERM -f 'codex.*app-server' 2>/dev/null || true
sleep 2

18.4 备份认证

mkdir -p "$CODEX_HOME/auth-backup"

if [ -f "$CODEX_HOME/auth.json" ]; then
  cp -a "$CODEX_HOME/auth.json" \
    "$CODEX_HOME/auth-backup/auth.json.$(date +%Y%m%d-%H%M%S).bak"
fi

18.5 删除失效认证

rm -f "$CODEX_HOME/auth.json"
rm -f "$CODEX_HOME/oauth.json"

18.6 写入最小配置

printf '%s\n' \
  'model = "gpt-5.3-codex-spark"' \
  'cli_auth_credentials_store = "file"' \
  '' \
  '[features]' \
  'apps = false' \
  > "$CODEX_HOME/config.toml"

chmod 600 "$CODEX_HOME/config.toml"

18.7 重新登录

codex login --device-auth

18.8 验证登录结构

codex login status
ls -l "$CODEX_HOME/auth.json"

18.9 进行真实模型测试

env -u OPENAI_API_KEY \
    -u CODEX_ACCESS_TOKEN \
    -u CODEX_API_KEY \
    CODEX_HOME="$CODEX_HOME" \
    codex exec \
    -m gpt-5.3-codex-spark \
    --skip-git-repo-check \
    --ephemeral \
    'Reply with exactly OK and nothing else.'

18.10 启动 Remote Control

codex remote-control stop 2>/dev/null || true
codex remote-control start
codex remote-control pair

十九、错误信息快速判断表

codex_apps token_revoked

MCP client for codex_apps failed
HTTP 401
token_revoked

含义:

Apps/Connectors OAuth 失效

临时处理:

[features]
apps = false

refresh token was revoked

Your access token could not be refreshed because your refresh token was revoked.

含义:

Codex 主认证失效

处理:

停止所有 Codex 进程
删除 auth.json
重新执行设备码登录
使用 codex exec 真实验证

You've hit your usage limit

含义:

认证成功,但当前模型额度耗尽

处理:

codex -m gpt-5.3-codex-spark

不要因此反复退出登录。


No such file or directory

如果 Codex 命令入口突然失效,并且此前移动过 $HOME/.codex

standalone 安装目录被移动

恢复:

mv "$HOME/.codex-broken-backup" "$HOME/.codex"
hash -r

managed standalone Codex install not found

含义:

当前 CODEX_HOME 中没有 standalone 安装

处理:

统一使用包含 packages/standalone 的正式 CODEX_HOME
或在当前 CODEX_HOME 下重新运行 Codex installer

Remote control is not enabled for this team

含义:

当前团队工作区可能未开放 Remote Control

检查:

  • 手机与服务器是否使用同一账号
  • 是否选择了同一个工作区
  • 个人工作区是否可用
  • 团队管理员是否启用了相关权限

二十、公开分享时必须删除的信息

发布日志或教程前,必须删除或替换:

真实主机名
公网 IP
SSH 地址
用户名
会话 ID
codex resume ID
设备登录码
Remote Control 配对码
access token
refresh token
id token
Cookie
Authorization header
完整 auth.json
团队名称
个人邮箱
精确额度恢复时间

推荐替换格式:

<SERVER_HOSTNAME>
<SERVER_IP>
<USERNAME>
<SESSION_ID>
<DEVICE_CODE>
<PAIRING_CODE>
<RESET_TIME>
<WORKSPACE_NAME>

可以公开:

错误类型
通用目录结构
脱敏后的命令
软件版本
配置字段
不包含 token 的布尔检查结果

二十一、核心经验

  1. codex_apps 错误与 Codex 主模型认证不是同一层问题。
  2. codex login status 不能替代真实模型请求验证。
  3. usage limit 表示认证成功,不是 token 失效。
  4. standalone 安装下,不要移动整个 $HOME/.codex
  5. Remote Control 要求当前 CODEX_HOME 中存在 standalone 程序。
  6. 配置、认证和 Remote Control 最好统一使用同一个正式 CODEX_HOME
  7. 出现认证问题时,只重置认证文件,不要删除整个安装目录。
  8. 所有设备码、配对码和 token 都不应出现在公开日志中。

更多推荐