Codex 服务器无浏览器登录:设备码、SSH 转发、auth.json 怎么选
Codex 无头登录首选 codex login --device-auth;设备码开不了就用 SSH 转发 1455 端口,再不行复制 auth.json,且一份只给一台机器。
文章目录

在 SSH 连着的服务器、容器或 WSL 里运行 codex login,终端会打印一个授权网址,你把它拿到自己电脑的浏览器里打开、登录、点同意,然后页面跳到一个打不开的地址,服务器那边一直等着。问题不在账号,而在最后一步:浏览器要把结果送回运行 Codex 的那台机器上的一个端口,而你的浏览器和 Codex 不在同一台机器上。
OpenAI 的认证文档给这种环境列了三条路线,按下面的顺序选:
- 手边有任何一台带浏览器的设备(手机也行),并且能在 ChatGPT 的安全设置里打开设备码登录:在服务器上运行
codex login --device-auth。这是文档的首选,不需要任何端口。 - 设备码开不了,但你是从自己的电脑 SSH 过去的:用
ssh -L把回调端口转到本机,照常走浏览器登录。 - 两样都做不到:在带浏览器的机器上登录,把
~/.codex/auth.json复制到服务器。这份文件只能给一台机器用。
如果跑 Codex 的不是坐在终端前的人,而是 CI 或定时脚本,上面三条都不合适,应该用 API key 或 access token,后面单独说。
先说清楚哪些是实际跑过的,哪些不是。截至 2026 年 10 月 2 日,Codex CLI 的稳定版是 0.160.0(2026 年 10 月 1 日发布),下面的内容都以这个版本为准。
实际跑过的(环境是 Ubuntu 24.04、glibc 2.39、OpenSSH 9.6p1、Codex CLI 0.160.0):
- 回环地址的简写
127.1在这台 Linux 上解析为 IPv4 回环地址。 - 一条目标写成
127.1的真实ssh -L转发能把请求送到只监听 IPv4 回环的服务。 - 同样写法的转发到达了 Codex 自己的回调监听端口:经隧道向
/auth/callback发一个不带任何参数的请求,得到400 Bad Request和State mismatch,与不经隧道时的响应相同。 - 1455 端口被占用时,
codex login打印的端口变成 1457。 codex login --device-auth打印的提示原文,包括一次性代码 15 分钟有效这一句。
没有做的:
- 任何一条路线都没有完成过一次登录,上面的检查到"监听端口收到请求"和"终端打印出提示"为止。
- 浏览器授权之后显示什么页面,没有见过。
- 把
auth.json复制到第二台机器上使用,以及令牌的刷新与撤销,都没有实际验证。 - 使用 musl 的系统(例如 Alpine)没有测。
- 隧道的两端在同一台主机上,没有跨两台机器的真实网络路径。
其余的命令、设置入口和报错文字来自 OpenAI 文档、0.160.0 的源码和 GitHub issue,出处随每条给出。
服务器上 codex login 走不完:回调要回到同一台机器的 1455 端口
不带参数的 codex login 会在本机启动一个临时的登录服务,监听本机回环地址的 1455 端口,然后打开浏览器。你在浏览器里登录之后,按文档的说法,"the browser returns your credentials to Codex":浏览器被重定向到回环地址上的 /auth/callback,登录服务收到后换取令牌并写入凭据。
回环地址指的是"浏览器所在的这台机器"。浏览器在你的笔记本上,登录服务在服务器上,重定向就落在了笔记本自己的 1455 端口,那里没有任何程序在听。这就是"认证网址无法回调"的全部原因,和服务器能不能上网、有没有装桌面环境无关。
在 Ubuntu 24.04 上运行 0.160.0 的 codex login,终端第一行是 "Starting local login server on" 加回环主机名和端口 1455,接着是 "If your browser did not open, navigate to this URL to authenticate:" 和一个 auth.openai.com 的授权网址。按源码,这段输出的末尾还有一句提示:"On a remote or headless machine? Use codex login --device-auth instead."
codex login --help 在 0.160.0 里只有三个登录相关的参数和一个子命令:
| 参数或子命令 | 帮助文字 | 用途 |
|---|---|---|
--device-auth | 无说明文字 | 设备码登录 |
--with-api-key | Read the API key from stdin | 从标准输入读 API key |
--with-access-token | Read the access token from stdin | 从标准输入读 access token |
status | Show login status | 查看当前登录方式 |
没有指定回调端口的参数,也没有 --no-browser。后者在 2025 年 12 月的一个 GitHub issue 里被提议过,0.160.0 里并不存在。旧教程里的 codex login --api-key 也已经失效,运行它会得到 The --api-key flag is no longer supported. 并以退出码 1 结束。如果你的 --help 输出里没有 --device-auth,说明版本早于 2025 年 10 月 3 日发布的 0.44.0,先按 Codex CLI 安装与配置升级。
三条路线怎么选:看浏览器、ChatGPT 设置和 SSH 转发
选路线只需要回答三个问题:有没有另一台带浏览器的设备,能不能改 ChatGPT 的安全设置,能不能从本机做 SSH 端口转发。

| 你的情况 | 路线 | 前提 | 主要限制 |
|---|---|---|---|
| 有手机或电脑的浏览器,个人账号能改安全设置,或工作区管理员已放行 | codex login --device-auth | ChatGPT 侧先打开设备码登录 | 一次性代码 15 分钟过期;文档标注为 beta |
| 设备码不可用,从自己的电脑 SSH 到服务器 | ssh -L 转发回调端口 | 本机有浏览器,SSH 允许端口转发 | 端口固定为 1455,被占用时回退到 1457 |
服务器只能通过跳板、docker exec 之类的方式进入,无法转发 | 复制 auth.json | 另一台机器已经登录,凭据以文件形式保存 | 一份文件一台机器;源机器重新登录可能让副本失效 |
| CI、定时任务、无人值守脚本 | API key 或 access token | 有 OpenAI API key,或托管工作区开通了 access token | 按 API 标准价格计费,部分依赖 ChatGPT 工作区的功能不可用 |
前三条登录的都是 ChatGPT 账号,用的是订阅里的额度;最后一条换了计费方式,不是"不用浏览器也能用订阅"的办法。
设备码登录:codex login --device-auth,15 分钟内输入一次性代码
设备码登录不需要回调:服务器上的 CLI 显示一个网址和一个代码,你在任何设备的浏览器里打开网址、登录、输入代码,CLI 自己向 OpenAI 轮询结果。文档对无头环境的原话是 "prefer device code authentication (beta)"。
第一步在 ChatGPT 里,不在终端里。文档写的是:个人账号在 ChatGPT 的安全设置里打开设备码登录,工作区账号由管理员在工作区权限里打开。OpenAI 成员在 issue #2798 里给过入口:个人账号是 chatgpt.com/#settings/Security,工作区管理员是 chatgpt.com/admin/permissions。开关的正式名称和默认状态,官方文字里没有写明;有用户在 issue 里说它叫 "Enable Codex Device Code Authorization",位于 Settings → Security。以你在安全设置页里实际看到的为准。
第二步在服务器上运行:
codex login --device-auth交互界面里也有同样的入口:首次启动 codex 时的三个选项中,第二项是 Sign in with Device Code。
0.160.0 实际打印的提示如下(一次性代码已替换成占位符):
Follow these steps to sign in with ChatGPT using device code authorization:
1. Open this link in your browser and sign in to your account
https://auth.openai.com/codex/device
2. Enter this one-time code (expires in 15 minutes)
XXXX-XXXXX
Continue only if you started this login in Codex. If a website or another person gave you this code, cancel.第三步在手机或电脑的浏览器里打开这个网址,登录 ChatGPT 账号,输入代码。按源码,CLI 这边在 15 分钟内持续轮询,授权通过后写入凭据。这一步之后的过程没有实际走过,以上面的文档和源码为据。最后一行警告要当真:这个代码等于"授权某个终端登录你的账号",只有你自己刚在 Codex 里发起登录时才输入,别人发来的代码不要输。
这条路线的边界有四个:
- 超时:15 分钟的有效期印在提示里。按源码,超时后终端报
device auth timed out after 15 minutes,重新运行命令拿新代码。 - 设置没开:有用户报告,网页会走完选账号和多因素验证之后才提示 "Enable device code authorization for Codex in ChatGPT Security Settings"。所以先去设置里确认,再发起登录。
- 工作区关闭了设备码:成员自己开不了。用户报告过的提示是 "Please contact your workspace admin to enable device code authentication",这时只能找管理员,或者改用下面两条路线。
- 手机验证:登录过程如果要求验证手机号,换成设备码同样会遇到,它只是替换了回调这一步。
SSH 端口转发:把 CLI 打印的端口转回本机,1455 或 1457
如果你是从自己的电脑 SSH 到服务器,可以让笔记本的 1455 端口直接通到服务器的 1455 端口,这样浏览器的回调落到本机端口后会被隧道送到服务器上的登录服务。这是 OpenAI 文档给的第二条路线。

在自己的电脑上建立带转发的 SSH 连接:
ssh -L 1455:127.1:1455 user@remote然后在这个 SSH 会话里运行:
codex login终端会打印登录服务启动的端口和一个授权网址。按文档,接下来把网址复制到本机浏览器打开,登录并同意,浏览器随后跳转到本机回环地址的 1455 端口,回调经隧道回到服务器上的登录服务。
关于这条命令的写法:OpenAI 文档里,-L 的中间那一段写的是回环主机名;上面写成 127.1,它是 IPv4 回环地址的标准简写,指向同一个目标,也就是服务器自己的回环接口。从 0.158.0(2026 年 9 月 28 日)起,登录服务只绑定 IPv4 回环地址,回调地址也改成了 IPv4 形式,所以把隧道目标明确写成 IPv4 回环与监听端一致。这个写法在 Linux 上的表现是实际观察到的。Ubuntu 24.04(glibc 2.39、OpenSSH 9.6p1)上,getent ahosts 127.1 返回 IPv4 回环地址;codex login 运行期间,用目标写成 127.1:1455 的 ssh -L 转发向 /auth/callback 发一个裸请求,响应是:
HTTP/1.1 400 Bad Request
State mismatchState mismatch 是 Codex 的回调服务在拒绝一个没有带授权状态参数的请求,说明请求确实经隧道到了它手里;不经隧道直接请求,得到的是同样的响应。这只证明转发通到了监听端口,并不是一次走完的登录:授权后的真实回调没有发生过。另外,这次检查里隧道两端是同一台主机,没有经过两台机器之间的网络。
转发目标由服务器一侧解析,所以起作用的是服务器的系统。使用 musl 的系统(例如 Alpine)没有测过,那里对这种简写的处理可能不同;转发不通时,改回 OpenAI 文档里用回环主机名的原始写法。
端口有两点文档没写到:
- 端口不能自选。按源码,回调端口写死在代码里,没有命令行参数,也没有配置项。
config.toml里的mcp_oauth_callback_port只管 MCP 的 OAuth,与codex login无关。 - 1455 被占用时会回退到 1457。这一点实际观察到了:先让别的进程占住 1455,再运行
codex login,打印出来的端口是 1457。这个行为是 0.128.0(2026 年 4 月 30 日)加入的;按源码,两个端口都被占用才会报Port … is already in use。文档里仍然只写 1455。
第二点直接影响隧道:服务器上的 1455 如果被别的进程占着,登录服务会起在 1457,只转发 1455 的隧道就收不到回调。先看 CLI 打印的端口,是 1457 就退出重连,把命令里的两个 1455 都换成 1457。也可以一开始就两个都转发。这只是根据回退行为给出的建议,文档里没有,下面这条命令也没有实际跑过:
ssh -L 1455:127.1:1455 -L 1457:127.1:1457 user@remote本机的对应端口也要空着。如果你的电脑上正好有另一个 Codex 在登录,或者别的程序占了 1455,隧道在本机这一端就建不起来。
WSL、VS Code Remote-SSH 上的端口占用和回调失败,OpenAI 成员在多个 issue 里的判断是本地网络配置(防火墙、VPN)导致的居多,建议直接换设备码登录,而不是继续调端口。
复制 auth.json:一份凭据只给一台机器,源机器别再重新登录
前两条都走不通时,文档给的退路是在有浏览器的机器上完成登录,再把缓存的凭据文件复制到无头机器。操作只有三步:在有浏览器的机器上运行 codex login,确认 ~/.codex/auth.json 存在,把它复制到服务器的同一路径。
文档给的命令:
ssh user@remote 'mkdir -p ~/.codex'
scp ~/.codex/auth.json user@remote:~/.codex/auth.json没有 scp 时用一条 ssh 完成:
ssh user@remote 'mkdir -p ~/.codex && cat > ~/.codex/auth.json' < ~/.codex/auth.json目标是 Docker 容器时:
CONTAINER_HOME=$(docker exec MY_CONTAINER printenv HOME)
docker exec MY_CONTAINER mkdir -p "$CONTAINER_HOME/.codex"
docker cp ~/.codex/auth.json MY_CONTAINER:"$CONTAINER_HOME/.codex/auth.json"复制完在服务器上执行 chmod 600 ~/.codex/auth.json。这一步文档没写,是处理密钥文件的常规做法;Codex 自己创建这个文件时用的也是 600 权限。
这份文件里是 auth_mode、tokens(其中有 id_token、access_token、refresh_token、account_id)和 last_refresh 等字段。文档的要求是把它当密码对待:不提交到仓库,不贴进工单,不在聊天里发。
源机器上找不到 auth.json 怎么办
凭据不一定存成文件。cli_auth_credentials_store 有四个取值:file 写入 auth.json,keyring 写入系统凭据库,auto 优先凭据库、不可用时退回文件,ephemeral 只在当前进程内存里。文档没有说默认值,0.160.0 源码里的默认值在所有系统上都是 file。如果你或管理员改成了 keyring 或 auto,~/.codex/ 下就可能没有这个文件,文档对此的说法是 "this method may not apply"。另外,设置过 CODEX_HOME 的话,文件在那个目录下,而不在 ~/.codex。
同一份 auth.json 能不能放到两台服务器上
不能长期这样用。OpenAI 的 CI/CD 认证指南写得很直接:"Do not share the same file across concurrent jobs or multiple machines."
原因在刷新机制。ChatGPT 登录的令牌会在使用过程中自动刷新:按该指南,last_refresh 超过大约 8 天,或者请求收到 401 时,Codex 会用 refresh_token 换一组新令牌并写回文件。换完之后旧的 refresh_token 就作废了。两台机器拿着同一份文件,先刷新的那台拿到新令牌,另一台手里的就成了旧的。OpenAI 成员在 issue #10332 里补充过,旧的 refresh token 在一段有限的时间内(大约一小时的量级)还能再用,之后永久失效。所以现象往往是两台机器都正常了一阵,然后其中一台突然要求重新登录。
要注意的是,复制本身就造成了"两台机器一份文件":源机器和服务器。源机器如果还在日常使用 Codex,就落在上面这种情况里。
在自己电脑上重新登录会不会影响服务器
很可能会。从 2026 年 6 月合并的 PR #27674 开始,每次 codex login(浏览器和设备码都算)都会先撤销并清除本机已有的凭据,codex logout 同样会向 OpenAI 发撤销请求。文档没有讲这对复制出去的副本意味着什么,下面是由这个行为推出的结论,没有实际测过:你在源机器上重新登录或登出时,被撤销的正是服务器上那份副本所用的令牌,服务器之后会在刷新时报
Your access token could not be refreshed because your refresh token was revoked. Please log out and sign in again.在这个推断成立的前提下,稳妥的用法是:复制之后,源机器不要再执行 codex login 和 codex logout;需要给第二台服务器凭据时,不要再复制同一份,而是让每台机器各自完成一次登录。源机器本身也要长期使用 Codex 的话,设备码登录比复制更合适,因为它让服务器拥有自己的一份凭据。
CI 和脚本不走浏览器登录:API key、CODEX_API_KEY 与 access token
无人值守的任务,文档的建议是 API key:"Use API key authentication for programmatic Codex CLI workflows, such as CI/CD jobs." 它完全不需要浏览器:
printenv OPENAI_API_KEY | codex login --with-api-key代价要先看清:API key 登录按 API 标准价格计费,不使用 ChatGPT 订阅里包含的额度;依赖 ChatGPT 工作区或云端服务的功能会受限或不可用,Codex cloud 必须用 ChatGPT 登录。两种计费的差别见 Codex API Key 和 ChatGPT 订阅怎么选。
只是跑 codex exec 的话,连 codex login 都可以省掉。按非交互模式文档,codex exec 默认复用已保存的登录;没有保存过登录时,在调用它的那一步设置环境变量 CODEX_API_KEY 即可,这个变量对 codex exec、codex review、TypeScript SDK 和 codex exec-server --remote 有效。两个容易弄错的地方:
- 交互式的
codex不读取CODEX_API_KEY,它只对上面列出的非交互入口生效。 - 环境变量表里列为凭据的是
CODEX_API_KEY和CODEX_ACCESS_TOKEN,OPENAI_API_KEY不在其中。只在环境里放一个OPENAI_API_KEY不等于登录,要么通过管道交给codex login --with-api-key,要么改用CODEX_API_KEY。
托管工作区还有第三种凭据:Codex access token,用于受信任的非交互流程。工作区所有者开启权限后,在 chatgpt.com/admin/access-tokens 创建,有效期可选 7、30、60 或 90 天,所有者和管理员可以撤销任何令牌。用法与 API key 对称:
printenv CODEX_ACCESS_TOKEN | codex login --with-access-token哪些套餐能用,OpenAI 的两个页面说法不一致:认证文档写的是 ChatGPT Enterprise 工作区,access token 页面写的是 Business 和 Enterprise 工作区。Business 工作区以管理后台里是否出现这个入口为准。
一定要在 CI 里用 ChatGPT 账号的额度,文档有一份标为 advanced 的做法:只在 auth.json 不存在时写入初始文件,让 Codex 在运行中刷新它,并把刷新后的文件保留给下一次任务,每个 runner 一份,不用于公开仓库。文档在同一页仍然说 "API keys are still the recommended option"。
用 codex login status 确认登录,按报错原文找原因
登录是否成功以 codex login status 为准:
codex login status
echo $?没有凭据时它输出 Not logged in,退出码是 1,这是实际运行的结果。按文档,有凭据时退出码是 0,并显示登录方式;源码里对应的文字是 Logged in using ChatGPT、Logged in using an API key 或 Logged in using access token。脚本里可以直接用退出码判断。如果显示的方式不是你想要的(比如想用订阅却显示 API key),先 codex logout 再按对应路线重新登录。
走不通时,先看终端或网页上的原话:
| 看到的提示 | 出处 | 原因 | 处理 |
|---|---|---|---|
device auth timed out after 15 minutes | 源码 | 一次性代码没在 15 分钟内用掉 | 重新运行 codex login --device-auth |
| 网页提示 Enable device code authorization for Codex in ChatGPT Security Settings | 用户报告 | 个人账号没开设备码登录 | 到 ChatGPT 安全设置里打开后重试 |
| Please contact your workspace admin to enable device code authentication | 用户报告 | 工作区禁用了设备码 | 找管理员,或改用 SSH 转发、复制凭据 |
device code login is not enabled for this Codex server | 源码 | 设备码接口返回 404 | 检查是否改过登录服务地址;改用浏览器登录 |
| 浏览器授权后跳到打不开的页面,终端一直等待 | 回调机制 | 回调没到服务器:没做转发,或转发的端口不是 CLI 打印的那个 | 按打印的端口重建隧道,或改用设备码 |
Port … is already in use | 源码 | 1455 和 1457 都被占用 | 结束占用端口的进程,通常是上一次没退出的 codex login |
refresh token was revoked 或 refresh token was already used | 源码 | 复制的凭据被源机器的重新登录撤销,或被另一台机器先刷新 | codex logout 后在这台机器上重新登录,不再共用文件 |
ChatGPT login is disabled. Use API key login instead. | 文档与源码 | 管理员用 forced_login_method 限定了登录方式 | 按提示换方式;反向的提示是 API key login is disabled. Use ChatGPT login instead. |
表里没有的情况,看登录日志。直接运行 codex login 时会写 codex-login.log,默认位置是 ~/.codex/log/codex-login.log。
公司网络如果用 TLS 代理或私有根证书,登录请求会因为证书不受信任而失败。文档的做法是在登录前指定证书文件,Codex 找不到这个变量时会退回 SSL_CERT_FILE:
export CODEX_CA_CERTIFICATE=/path/to/corporate-root-ca.pem
codex login --device-auth授权已经完成、终端却以 Token exchange failed 和 403 结束,属于另一类问题,按 Codex 令牌交换失败 403排查。codex login status 显示已登录、发请求时才报 401,则看 Codex 报 401 Incorrect API key provided。
VS Code Remote SSH 里 Codex 无法账号登录怎么办
在 VS Code 的远程终端里运行 codex login --device-auth,不需要另外在扩展里登录。依据是文档的说明:CLI 和 IDE 扩展共用同一份缓存的登录信息,而 Remote SSH 下两者都运行在远程主机上,读的是远程主机的 ~/.codex/auth.json。
Remote SSH 下账号登录失败,原因和普通 SSH 一样:登录服务起在远程主机上,浏览器在你的电脑上。VS Code 的自动端口转发能不能把这次回调送过去,OpenAI 没有给过说明;相关 issue 里官方的答复是使用设备码登录,其中 issue #12263 在 2026 年 8 月 5 日以 "Device-code authentication is implemented and documented." 关闭。设备码在你的账号或工作区里不可用时,再回到 SSH 转发或复制 auth.json。





