- Rust 100%
| src | ||
| .gitignore | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| config.example.toml | ||
| LICENSE | ||
| README.md | ||
Codex subscription proxy
This is a small HTTP proxy for the ChatGPT subscription backend used by Codex
CLI. It manages auth.json and exposes:
POST {prefix}/responses(SSE response streaming)POST {prefix}/responses/compactGET {prefix}/models
The prefix is configurable and defaults to /v1.
Response bodies, statuses, and errors from the upstream Codex backend are passed through without modification. Hop-by-hop headers, cookies, upstream infrastructure details, and browser policies tied to the upstream origin are removed from response headers.
Run
Copy config.example.toml, set a strong proxy access_token, and point
auth_file at the file-backed Codex CLI auth.json. Then run:
codex-subscription-proxy --config ./config.toml
Call the proxy with its own bearer token:
curl -N http://127.0.0.1:8787/v1/responses \
-H 'Authorization: Bearer replace-with-a-long-random-secret' \
-H 'Content-Type: application/json' \
--data-binary @request.json
The proxy replaces that local authorization header with the current ChatGPT
bearer token and adds the account/workspace header from auth.json.
Omit client_version to automatically use the latest stable Codex CLI release
from GitHub. The proxy resolves the
version before starting the HTTP service and checks for updates every hour.
Only stable rust-vX.Y.Z releases are considered; drafts, prereleases, and other
packages are ignored. Initialization and version updates produce INFO logs.
New versions apply to subsequent requests without restarting the proxy.
Automatic discovery requires GitHub access at startup. If the initial lookup
fails, startup fails; if a later check fails, the proxy logs a warning and keeps
the last known version until a subsequent hourly check succeeds. Set
client_version = "0.155.1" explicitly to pin a version and disable all GitHub
checks. The active version supplies the default version header and /models
client_version query parameter; caller-provided values still take precedence.
Architecture
Each request follows a short, stateless forwarding path: authenticate the local
bearer token, read a bounded request body, reload/refresh the Codex
credentials, sanitize and replace authentication headers, and call the matching
upstream route. Unary response bodies are passed through directly; the
Responses SSE body is streamed as it arrives. Response headers are sanitized
before being returned. An upstream 401 invokes one guarded auth
reload/refresh and one replay of the buffered request.
The auth manager is the only component that writes auth.json. Its async lock
prevents two requests in this process from rotating the same refresh token
concurrently. It re-reads the file after taking the lock so a credential update
made by Codex CLI or another process can be adopted before it calls the token
authority.
Credential behavior
The proxy follows the Codex CLI refresh policy found in the adjacent source clone:
- Refresh a parseable access-token JWT when it has five minutes or less remaining.
- If the access token is opaque/unparseable, use Codex's eight-day
last_refreshfallback. - Reload
auth.jsonunder a process-wide refresh lock before rotating credentials. - Preserve fields omitted by the OAuth refresh response and preserve unknown JSON fields.
- Atomically replace
auth.jsonwith mode0600on Unix after a successful refresh. - On an upstream
401, reload/refresh and retry the request once.
This MVP supports Codex's file-backed, managed ChatGPT auth (auth_mode = "chatgpt") only. It does not read OS keyrings, proxy WebSockets, keep a
Cloudflare cookie jar, validate Responses request JSON, or expose other ChatGPT
backend routes. Request bodies are bounded and buffered to permit one
authentication retry; SSE response bodies are streamed directly. The ChatGPT
subscription backend is internal and implementation-specific, so its behavior
can change independently of this project.
Keep the default loopback bind unless TLS and suitable access controls are provided by a trusted front end. Anyone holding the configured proxy access token can consume the ChatGPT account's Codex allowance.