OpenAI via ChatGPT subscription (Codex proxy)
June 22, 2026 · View on GitHub
Unofficial and ToS-risky. This routes inference to your ChatGPT subscription through the Codex backend, the way
codex logindoes. It is not a supported way for a third-party app to bill a user's subscription. Anthropic and Google closed their equivalents in 2026; OpenAI may follow, and accounts that abuse it can be limited or banned. Decide with eyes open. The supported alternative is a normal OpenAI API key (api_kind = "openai_compatible",auth_env = "OPENAI_API_KEY").
Why the Apps SDK does not work for this
The Apps SDK OAuth authenticates users into your MCP server and issues tokens for your tools. It does not grant a token to call OpenAI inference on the user's plan. The only path that does is the Codex one below.
How it works here
router (api_kind="openai_codex")
→ codex_backend.make_codex_async_call_provider
→ POST {base_url}/responses (https://chatgpt.com/backend-api/codex/responses)
Authorization: Bearer <access_token from ~/.codex/auth.json, auto-refreshed>
chatgpt-account-id: <account_id>
body: Responses API schema, stream=true (SSE)
← SSE aggregated back into the router's response shape
- Token source:
codex_auth.CodexAuthreads~/.codex/auth.json(access_token,refresh_token,id_token,account_id; both top-level and nestedtokenslayouts are accepted). - Refresh: when the access token's JWT
expis near, it refreshes againsthttps://auth.openai.com/oauth/tokenwith the public Codex client idapp_EMoamEEZ73f0CkXaXp7hrannand writes the new tokens back toauth.json. - Wire shape: the Codex endpoint speaks the Responses API (not
chat/completions) and streams SSE;
codex_backendtranslates the router's chat-style request toinputitems and folds theresponse.output_text.delta/response.completedevents back into text + usage.
Setup
# 1. Authenticate (opens a browser; "Sign in with ChatGPT")
codex login # writes ~/.codex/auth.json
# 2. Start the shim; it picks up auth.json lazily on the first codex call
python -m hosts.python_shim --config hosts/python_shim/config.live.lua \
--codex-auth ~/.codex/auth.json
--codex-auth defaults to ~/.codex/auth.json. Treat that file like a
password — it holds bearer tokens.
Caveats
- The backend endpoint is undocumented and can change without notice; if the
Responses event names or the
/responsespath change,codex_backendneeds updating. - The live streaming call is not covered by tests (no subscription in CI).
The token read/refresh, request translation, header building and SSE
aggregation are unit-tested in
hosts/python_shim/tests/test_codex.py. - Tool calls are not yet translated to the Responses API tool schema; v1 sends
text in / text out. Add tool translation in
build_codex_bodywhen needed.