A Go reverse proxy that exposes a standard OpenAI-compatible REST API backed by ChatGPT Plus OAuth accounts instead of a billing API key.
It reads from the OpenAI codex-rs auth flow (PKCE browser login or device-code login) and rotates between a pool of Plus accounts to spread rate-limit load.
| Feature | Detail |
|---|---|
| PKCE browser login | Opens auth.openai.com in your browser; callback on localhost:1455 |
| Device code login | No browser needed – enter a short code on a separate device |
| Account pool | Round-robin rotation, per-account cooldown after 429 |
| Automatic token refresh | Transparently refreshes expired tokens on 401; background refresh every 8 days |
| Chat Completions API | POST /v1/chat/completions with streaming (SSE) |
| Responses API | POST /v1/responses – supports web_search_preview and other tools |
| Model aliases | compact / codex-mini / mini → codex-mini-latest |
| Model list | GET /v1/models |
# 1. Build
go build -o codex-reverse .
# 2. Add your first Plus account (opens browser)
./codex-reverse login pkce --name alice
# 3. Add your second Plus account
./codex-reverse login pkce --name bob
# 4. (Optional) use device-code flow instead
./codex-reverse login device --name charlie
# 5. Verify accounts
./codex-reverse accounts list
# 6. Start the proxy
./codex-reverse serve --port 8080Then point any OpenAI-compatible client at it:
export OPENAI_BASE_URL=http://localhost:8080/v1
export OPENAI_API_KEY=dummy # auth is handled by OAuth tokens; key is ignored
# Chat Completions
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o","messages":[{"role":"user","content":"hello"}],"stream":true}'
# Responses API with web_search
curl http://localhost:8080/v1/responses \
-H "Content-Type: application/json" \
-d '{
"model": "codex-mini-latest",
"input": "What is the latest news about OpenAI?",
"tools": [{"type": "web_search_preview"}]
}'
# Use the "compact" alias
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"compact","messages":[{"role":"user","content":"hello"}]}'# List accounts
./codex-reverse accounts list
# Force-refresh tokens for a specific account
./codex-reverse accounts refresh alice
# Refresh all accounts
./codex-reverse accounts refresh
# Remove an account
./codex-reverse accounts remove aliceRequest arrives
│
▼
Pick next available account (round-robin)
│
├─ 429 Too Many Requests ──► mark account rate-limited (60s cooldown)
│ retry with next account
│
├─ 401 Unauthorized ────────► refresh OAuth tokens
│ retry once; if still 401 → rotate account
│
└─ 2xx / 4xx / 5xx ────────► stream response back to client
If all accounts are rate-limited, the proxy returns 503.
Mirrors codex-rs source code exactly:
PKCE browser flow (login pkce)
- Generate 64-byte random
code_verifier→ BASE64URL-NOPAD code_challenge = BASE64URL-NOPAD(SHA256(code_verifier))- Start local HTTP server on
:1455 - Open
https://auth.openai.com/oauth/authorize?response_type=code&code_challenge_method=S256&... - Receive callback at
/auth/callback, verifystate - Exchange code at
https://auth.openai.com/oauth/token(authorization_code grant) - Optionally exchange
id_tokenfor a session API key (sess-...)
Device code flow (login device)
POST https://auth.openai.com/api/accounts/deviceauth/usercode- Display
verification_url+user_code - Poll
https://auth.openai.com/api/accounts/deviceauth/tokenuntil 200 - Server returns
{authorization_code, code_verifier, code_challenge} - Exchange at token endpoint (authorization_code grant)
Token refresh (automatic)
POST https://auth.openai.com/oauth/tokenwithgrant_type=refresh_token- Triggered on 401 responses and background check every 8 days
| Flag | Default | Description |
|---|---|---|
--store PATH |
~/.codex-reverse |
Directory for accounts.json |
serve --port |
8080 |
Proxy listen port |
serve --host |
127.0.0.1 |
Proxy bind address |
serve --api-base |
https://api.openai.com |
Upstream API base |
serve --retries |
3 |
Max account rotations per request |
| Alias | Resolves to |
|---|---|
compact |
codex-mini-latest |
codex-compact |
codex-mini-latest |
codex |
codex-mini-latest |
mini |
codex-mini-latest |
codex-mini |
codex-mini-latest |
Accounts are stored in ~/.codex-reverse/accounts.json (mode 0600).
The file contains OAuth tokens – keep it private.
{
"accounts": [
{
"name": "alice",
"email": "alice@example.com",
"plan_type": "plus",
"access_token": "eyJ...",
"refresh_token": "...",
"id_token": "eyJ...",
"api_key": "sess-...",
"last_refresh": "2026-03-18T12:00:00Z"
}
]
}