Codex CLIをSSH先・ヘッドレス環境でログイン:ブラウザなしの3経路
ブラウザのないSSH先では--device-authのデバイスコード認証が第一候補です。使えなければ1455番ポートの転送かauth.jsonのコピーを選びます。
目次

SSH接続先のサーバーやコンテナでcodex loginを実行すると、URLが表示されたまま先へ進みません。ブラウザのないマシンでChatGPTアカウントのままCodex CLIにログインする方法は3つあり、OpenAIが認証ドキュメントで最初に勧めているのはデバイスコード認証です。
codex login --device-auth表示されたURLを手元のPCやスマートフォンのブラウザで開き、サインインして、ターミナルに出ているワンタイムコードを入力します。コードの有効時間は15分です。この方法はChatGPT側の設定でデバイスコードによるログインを有効にしておく必要があり、ワークスペースのアカウントでは管理者が許可していないと使えません。その場合は、SSHで1455番ポートを転送して通常のブラウザログインを通すか、ブラウザのあるマシンでログインして~/.codex/auth.jsonをコピーします。
以下の内容のうち、実際に動かして確かめた範囲と、そうでない範囲ははっきり分かれます。2026年10月2日にUbuntu 24.04(glibc 2.39、OpenSSH 9.6p1、Codex CLI 0.160.0)で実行して観察したのは次の5点です。
- ループバックアドレスの短縮表記
127.1が、IPv4のループバックアドレスとして解決されること - その表記を転送先にした実際の
ssh -Lが、IPv4のループバックだけで待ち受けるサーバーに通信を届けること - 同じ形の転送が、
codex loginの起動したコールバック待ち受けに届くこと。認証情報を付けない素のリクエストには400 Bad RequestとState mismatchが返りました - 1455番が使用中のとき、
codex loginが1457番に切り替えて起動すること codex login --device-authの表示文と、コードの有効期限が15分であること
一方、どの経路でもログインを最後まで完了させてはいません。ブラウザで承認したあとの画面、auth.jsonを別のマシンにコピーして使う場合の動作、トークンの更新と失効の挙動は試しておらず、これらはOpenAIのドキュメントとCodex CLI 0.160.0のソースコードに基づく説明です。Alpineなどmusl系の環境も未確認で、トンネルは両端が同じホストの構成で確かめたものです。
codex loginがSSH先で終わらない理由:コールバックが届かない
通常のcodex loginは、Codexを実行しているマシンの上に一時的なログイン用サーバーを立て、ブラウザで認証を済ませたあと、そのサーバーへ認証結果を戻してもらう仕組みです。ドキュメントは「サインイン後、ブラウザが認証情報をCodexに返す」と説明しています。
戻り先は、Codexが動いているマシン自身のループバックアドレスです。SSH先でURLをコピーして手元のPCのブラウザで開くと、サインインまでは進みますが、最後のリダイレクトは手元のPCのループバックアドレスに向かいます。そこでは何も待ち受けていないため、ブラウザは接続エラーになり、サーバー側のCodexは待ち続けます。
0.160.0のCLIも、この状況を前提にした案内を出します。ブラウザのないLinuxでcodex loginを実行すると、Starting local login server onに続けてループバックのホスト名と1455番のアドレスが表示され、次にIf your browser did not open, navigate to this URL to authenticate:とauth.openai.comの認証用URLが出ました。ソースコードでは、そのあとにOn a remote or headless machine? Use codex login --device-auth instead.という案内が続きます。
ドキュメントが通常のログインで失敗する場面として挙げているのは次の2つです。
- CLIをリモートまたはヘッドレスな環境で動かしている
- ローカルのネットワーク設定が、CodexがOAuthトークンを受け取るためのループバック宛てコールバックを遮断している
2つ目はブラウザのあるマシンでも起こります。WSLやVS CodeのRemote-SSHでコールバックが届かないという報告に対して、OpenAIはファイアウォールやVPNなどローカルのネットワーク構成が原因であることが多いとして、デバイスコード認証を案内しています(issue #3927、issue #12263)。
なお、0.160.0のcodex login --helpに出るログイン用フラグは--with-api-key、--with-access-token、--device-authの3つだけです。コールバックのポートを指定するフラグや、ブラウザを開かないための--no-browserのようなフラグはありません。Codex CLI自体をまだ入れていない場合は、先にCodex CLIのインストールと設定を済ませてください。
どの経路を選ぶか:別端末・ポート転送・自動化で分かれる
判断に使う条件は4つです。ブラウザのある別の端末が手元にあるか、ChatGPTのセキュリティ設定を変えられるか、SSHのポート転送ができるか、操作するのが人か自動化か。
| 状況 | 使う経路 | 前提 | 気をつける境界 |
|---|---|---|---|
| 別の端末にブラウザがあり、ChatGPTの設定を変えられる | デバイスコード認証 | セキュリティ設定で有効化済み。ワークスペースは管理者の許可 | コードは15分で失効。ベータ扱い |
| 設定は変えられないが、手元のPCからSSHのポート転送ができる | 1455番ポートを転送して通常のログイン | 手元のPCにブラウザ。転送が禁止されていないこと | 1455が使用中なら1457に切り替わる |
| どちらもできない | 別のマシンでログインしてauth.jsonをコピー | 認証情報がファイルに保存されていること | 1ファイル1マシン。元のマシンの再ログインで失効しうる |
| CIやスクリプトなど、人が操作しない | APIキー、CODEX_API_KEY、アクセストークン | APIの課金、または管理対象ワークスペース | ChatGPTプランの利用枠ではなくAPI料金になる |
上の3つはどれもChatGPTアカウントでのサインインで、プランに含まれる利用枠をそのまま使います。4つ目だけは認証の種類が変わり、支払いと使える機能も変わります。

デバイスコード認証:--device-authとコードの15分
サーバー側にブラウザもポート転送も要らないのがこの経路です。認証の結果をサーバーへ送り返す必要がなく、CLIの側からOpenAIへ問い合わせて完了を確認するためです。ドキュメントは「リンクをブラウザで開く」としか書いていませんが、この仕組みなら、ブラウザは手元のPCでもスマートフォンでも構わないことになります。
ドキュメントの手順は3段階です。
- ChatGPTのセキュリティ設定でデバイスコードによるログインを有効にする。個人アカウントは自分で、ワークスペースは管理者が権限設定で行う
- ターミナルで
codex login --device-authを実行する。初回起動の画面なら「Sign in with Device Code」を選ぶ - 表示されたリンクをブラウザで開いてサインインし、ワンタイムコードを入力する
設定の場所は、OpenAIのメンバーがissue #2798で示しています。個人アカウントはchatgpt.com/#settings/Security、ワークスペース管理者はchatgpt.com/admin/permissionsです。スイッチの正式な表示名、初期状態、対象プランは公開ドキュメントに記載がありません。ユーザーの報告では、設定のセキュリティ欄に「Enable Codex Device Code Authorization」という名前で出ています。見当たらない場合は、セキュリティ設定の中でデバイスコードに関する項目を探してください。
0.160.0でcodex login --device-authを実行すると、Follow these steps to sign in with ChatGPT using device code authorization:に続いて、ターミナルに次の3つが出ます。ここまでは実際の表示で確かめた内容で、コードを入力したあとの流れは試していません。
- 認証用のURL:
https://auth.openai.com/codex/device - ワンタイムコードと「expires in 15 minutes」の注記
- 自分がCodexで始めたログインのときだけ続行し、Webサイトや他人から渡されたコードなら中止するように、という警告
最後の警告は読み飛ばさないでください。デバイスコードは、コードを入力した人のアカウントを、コードを発行した側の端末に結びつけます。自分で実行したのではないコードを入力すると、他人の端末に自分のアカウントでログインさせることになります。
ソースコードによると、15分以内に入力しなかった場合、CLIはdevice auth timed out after 15 minutesで終了します。もう一度実行すれば新しいコードが出ます。終わったら次のコマンドで確認します。
codex login status認証情報がない状態ではNot logged inと表示され、終了コードは1でした。ドキュメントとソースコードによれば、ChatGPTアカウントの認証情報が保存されているとLogged in using ChatGPTと表示され、終了コードは0になります。
--device-authが安定版に入ったのは2025年10月3日の0.44.0で、ベータとして公式に案内されたのは2025年12月8日です。それより前に書かれた手順がauth.jsonのコピーだけを紹介しているのは、この経路がまだなかったためです。
ワークスペースでこの機能が無効になっていると、メンバーは利用できません。「Please contact your workspace admin to enable device code authentication」と表示されたというユーザー報告があります(issue #9253)。管理者に有効化を頼めない場合は、次の2つの経路に進みます。また、ログイン時に電話番号の確認を求められるアカウントでは、デバイスコード認証でもその確認は省略されないという報告が未解決のまま残っています。
SSHのポート転送で通常のログイン:1455と予備の1457
手元のPCからポート転送ができるなら、通常のブラウザログインをそのまま使えます。サーバー側のログイン用サーバーが待ち受けるポートを、SSHのトンネルで手元のPCに引き出します。
手元のPCから、転送つきでサーバーに接続します。
ssh -L 1455:127.1:1455 user@remoteそのSSHセッションの中でcodex loginを実行し、表示されたアドレスを手元のPCのブラウザで開きます。ドキュメントの説明どおりなら、認証後のリダイレクトは手元のPCの1455番に向かい、トンネルを通ってサーバー上のCodexに届きます。

転送先の書き方について補足します。OpenAIのドキュメントは転送先をループバックのホスト名で書いています。上のコマンドは同じ宛先を、IPv4ループバックアドレスの短縮表記である127.1で書いたものです。0.158.0(2026年9月28日)以降、Codexのログイン用サーバーはIPv4のループバックアドレスだけで待ち受けるようになりました(PR #47927)。ホスト名のほうはマシンによってIPv6が先に解決されることがあるため、IPv4を明示した書き方は待ち受け側の動作と一致します。
この書き方は、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 mismatchが返り、トンネルを通さずに直接送った場合と同じ応答でした。OAuthのstateを持たないリクエストをCodexのコールバック処理が拒否した結果なので、この形の転送がCodex自身の待ち受けに届くことは分かります。ただし、分かるのはそこまでです。ブラウザでの承認を経てログインが完了するところまでは通していません。また、トンネルの両端が同じホストの構成だったので、別々のマシンの間のネットワーク経路は含まれていません。
転送先の解釈はサーバー側で行われます。Alpineなどmusl系の環境でこの短縮表記が通るかは未確認です。受け付けない環境では、OpenAIのドキュメントの書き方に置き換えてください。
ポートについては、ドキュメントとソースコードで情報の新しさが違います。
| 項目 | ドキュメントの記載 | 0.160.0のソースコード |
|---|---|---|
| ポート | 既定は1455 | 1455固定。使用中なら1457に自動で切り替え(0.128.0、2026年4月30日以降)。0.160.0で実際に切り替わることを観察 |
| 待ち受けアドレス | ループバックのホスト名 | IPv4のループバックアドレスのみ(0.158.0以降) |
| ポートの変更 | 記載なし | フラグも設定キーもない。mcp_oauth_callback_portはMCPのOAuth専用 |
新しいのはソースコードのほうです。1457番への切り替えはPR #19334で入りました。この切り替えはソースコードの記述だけでなく、実際の動作でも確かめられています。1455番を別のプロセスで埋めた状態でcodex loginを実行すると、起動時の表示が1457番になりました。
ここから導ける注意点が1つあります。Codexが1457番で起動した場合、1455番だけを転送したトンネルにはコールバックが届かないはずです。これは挙動からの推論で、ドキュメントには書かれていません。codex loginが表示したポート番号を見て、1457になっていたらそのポートを転送し直してください。最初から両方を転送しておく書き方も考えられます。次のコマンドは提案で、実行して確かめたものではありません。
ssh -L 1455:127.1:1455 -L 1457:127.1:1457 user@remoteソースコードによると、両方のポートが使用中のときだけ、Port … is already in useで失敗します。前回のcodex loginが残っていないかを確認してください。
VS CodeのRemote-SSHやJetBrains Gatewayが行う自動のポート転送でこのログインが通るかどうかについて、OpenAIの公式な説明はありません。確実なのは、上のように自分でssh -Lを指定する方法です。
auth.jsonをコピーする:1ファイル1マシンと再ログインの失効
デバイスコードも使えず、ポート転送も禁止されている環境では、ブラウザのあるマシンでログインを済ませ、保存された認証キャッシュをサーバーへ運びます。ドキュメントの手順は次のとおりです。
- ブラウザのあるマシンで
codex loginを実行する ~/.codex/auth.jsonができていることを確認する- そのファイルを、ヘッドレス側の
~/.codex/auth.jsonにコピーする
ssh user@remote 'mkdir -p ~/.codex'
scp ~/.codex/auth.json user@remote:~/.codex/auth.jsonscpが使えない場合の1行版もドキュメントに載っています。
ssh user@remote 'mkdir -p ~/.codex && cat > ~/.codex/auth.json' < ~/.codex/auth.jsonDockerコンテナへ入れる場合です。
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として自分だけが読めるようにしておきます。これはドキュメントにはない一般的な用心です。ドキュメントはこのファイルを「パスワードと同じように扱う」よう求めています。中身はアクセストークンなので、リポジトリにコミットしない、チケットに貼らない、チャットで共有しない、の3点です。
この経路には、手順より先に知っておくべき境界が3つあります。
認証情報がファイルに保存されていること。 保存先は設定cli_auth_credentials_storeで決まります。値はfile、keyring、auto、ephemeralの4つで、ドキュメントは既定値を明記していませんが、0.160.0のソースコードでは全OSでfileです。keyringやautoに変えている場合、または管理者が保存先を指定している場合は、auth.jsonができないことがあり、ドキュメントも「この方法は当てはまらないかもしれない」としています。環境変数CODEX_HOMEを自分で設定している場合、ファイルの場所はそのディレクトリの直下になり、ディレクトリは事前に作っておく必要があります。
1つのファイルは1台のマシンで使うこと。 同じログインを2台のサーバーで使い回すことはできません。CI/CD向けの認証ガイドは「同じファイルを並行するジョブや複数のマシンで共有しない」と書いています。理由はトークンの更新にあります。Codexは使用中にトークンを自動で更新し、新しい値をファイルに書き戻します。同ガイドによると、更新が走るのは最後の更新からおよそ8日を過ぎたときと、401が返ったときです。2台が同じファイルを持っていると、先に更新した側が新しいリフレッシュトークンを受け取り、もう一方の手元には使用済みのトークンが残ります。OpenAIのメンバーはissue #10332で、リフレッシュトークンは1時間程度の限られた時間内なら再利用できるが、その後は完全に無効になると説明しています。2台がしばらく両方動いたあと片方だけ落ちるのは、このためです。サーバーが2台あるなら、それぞれで別々にログインします。
元のマシンで再ログインやログアウトをすると、コピーが無効になりうること。 2026年6月12日にマージされたPR #27674以降、codex loginはブラウザ経由でもデバイスコードでも、開始前にそのマシンに保存されている認証情報を失効させてから消します。codex logoutも同じく失効処理を行います。ここから先は推論で、ドキュメントに記載はなく、実際に試して確かめたものでもありません。サーバーにコピーしたauth.jsonは元のマシンと同じトークンを持っているので、元のマシンでcodex loginをやり直したりcodex logoutしたりすると、サーバー側のコピーも使えなくなる可能性があります。ソースコードでは、失効したリフレッシュトークンで更新しようとしたときのメッセージは次のとおりです。
Your access token could not be refreshed because your refresh token was revoked. Please log out and sign in again.これを避けるには、元のマシンでログインしてコピーしたあと、そのマシンでは再ログインもログアウトもしないことです。手元のPCでもCodexを使い続けるなら、コピーよりデバイスコード認証のほうが向いています。サーバーが自分でログインするので、手元のPCの認証情報と無関係になるためです。
CIや自動実行はAPIキーかアクセストークン:課金が変わる
人が操作しない環境では、ChatGPTログインを持ち込むよりAPIキーを使うのが公式の推奨です。ドキュメントは「CI/CDジョブのようなプログラムからのCodex CLI利用にはAPIキー認証を使う」と書いています。ブラウザは要りません。
printenv OPENAI_API_KEY | codex login --with-api-key以前の--api-keyフラグは廃止されていて、使うとThe --api-key flag is no longer supported.と表示されて終了します。キーは上のように標準入力から渡します。
ただし、これはChatGPTプランをブラウザなしで使う方法ではありません。APIキーでの利用は標準のAPI料金で課金され、プランに含まれる利用枠は使われません。ChatGPTのワークスペースやクラウド側のサービスに依存する機能は制限されるか使えず、Codex cloudにはChatGPTでのサインインが必要です。どちらで払うべきかはCodex APIキーとChatGPTサブスクの違いで比べられます。
非対話実行のcodex execは、既定では保存済みのCLI認証をそのまま使います。ログインせずにキーを渡したい場合は環境変数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を環境に置いただけではcodex execの認証情報にはなりません。
管理対象のワークスペースには、もう1つの選択肢としてCodexアクセストークンがあります。ワークスペースのオーナーが権限を有効にしたうえでchatgpt.com/admin/access-tokensで発行し、有効期限は7日、30日、60日、90日から選べます。
printenv CODEX_ACCESS_TOKEN | codex login --with-access-token対象プランの記載はOpenAIのページ間で食い違っています。認証ドキュメントは「ChatGPT Enterpriseワークスペース」、アクセストークンのページは「現在はChatGPT BusinessとEnterpriseのワークスペース」としています。Businessで使えるかどうかは、自分のワークスペースの管理画面で確かめてください。
どうしてもChatGPTアカウントの認証をCIで使いたい場合について、OpenAIは上級者向けの手順を用意しています。auth.jsonはファイルがないときだけ投入し、実行中の更新はCodexに任せ、更新後のファイルを次のジョブのために保存し、公開リポジトリでは使わない、という内容です。それでも自動化にはAPIキーが推奨のままです。
ログインできないときのエラー文とcodex-login.log
エラー文は原因をかなり具体的に示します。出どころの種類とあわせて整理します。
| 表示される文 | 出どころ | 意味と対処 |
|---|---|---|
device code login is not enabled for this Codex server. | ソースコード | デバイスコードの受付先が404を返した。ポート転送かファイルのコピーに切り替える |
| Enable device code authorization for Codex in ChatGPT Security Settings | ユーザー報告(ブラウザ側) | 個人アカウントで未設定。セキュリティ設定で有効にして再実行 |
| Please contact your workspace admin to enable device code authentication | ユーザー報告 | ワークスペースで無効。管理者に依頼するか別の経路へ |
device auth timed out after 15 minutes | ソースコード | コードが失効。再実行して新しいコードを入力 |
Port … is already in use | ソースコード | 1455と1457の両方が使用中。残っているログイン処理を終了する |
refresh token was revokedを含む文 | ソースコード | 別の場所で再ログインかログアウトが行われた。ログインし直すか、コピーし直す |
refresh token was already usedを含む文 | ソースコード | 同じauth.jsonを別のマシンやジョブが先に更新した。マシンごとにログインする |
ChatGPT login is disabled. Use API key login instead. | ソースコード | 管理者がforced_login_methodでAPIキーに限定している |
API key login is disabled. Use ChatGPT login instead. | ソースコード | 逆に、ChatGPTログインに限定されている |
最後の2つは管理者による制限です。ドキュメントによれば、許可されていない方法でログインしていると、Codexはユーザーをログアウトさせて終了します。個人で回避する方法はなく、指定された方法に合わせることになります。
表にない失敗は、ログを見ます。codex loginを直接実行したときのログは、既定では~/.codex/log/codex-login.logに書かれます。
社内のTLS検査プロキシや独自のルート証明書がある環境では、ログインの通信が証明書エラーで止まることがあります。その場合は、ログインの前にルート証明書を指定します。この変数がなければSSL_CERT_FILEが使われ、ログインだけでなくHTTPSとWebSocketの通信にも適用されます。
export CODEX_CA_CERTIFICATE=/path/to/corporate-root-ca.pem
codex login --device-authブラウザでの認証までは終わるのに、その後のトークン交換が403で終わる場合は原因が別にあります。Codexのトークン交換が403で失敗で、ログイン・プロキシ・地域・認証キャッシュを順に切り分けられます。codex login statusではログイン済みなのに実行時に401が返る場合は、Codexの401「Incorrect API key」の見分け方が当てはまります。
まとめると、最初に試すのはcodex login --device-authです。設定を変えられないなら1455番ポートの転送、それも無理ならauth.jsonのコピーで、コピーした場合は元のマシンで再ログインしないこと、1ファイルを1台だけで使うことの2点を守ります。どの経路でも、最後はcodex login statusの表示と終了コードで確かめられます。





