Route a ChatGPT subscription through Aperture
Last validated:
In passthrough mode, Aperture forwards each client's own credential to the upstream provider instead of injecting a shared API key. This guide uses passthrough to route a ChatGPT subscription: the Codex CLI signs in to the subscription and holds an OAuth token, and Aperture forwards that token to the ChatGPT backend unchanged.
A ChatGPT subscription and an OpenAI platform API key are separate systems that use different endpoints and credentials:
| Endpoint | Credential | Billing |
|---|---|---|
chatgpt.com/backend-api/codex | ChatGPT OAuth token | ChatGPT subscription (Plus, Pro, Team, Enterprise) |
api.openai.com/v1 | API key with the api.responses.write scope | Platform API credits |
The ChatGPT backend does not accept API keys, and the platform API does not accept ChatGPT OAuth tokens. This guide covers the subscription (OAuth) path. To route platform API keys instead, refer to use Codex with Aperture. If you have both kinds of user, configure a separate provider for each.
Aperture routes requests based on the model name, not the LLM client. Any LLM client configured to use Aperture can access any provider your admin has set up. Refer to the provider compatibility reference for the full list of supported providers and API formats.
Prerequisites
Before you begin, you need:
- An Aperture instance accessible from your device, and admin access to edit its configuration.
- A grant that permits the Codex models for the Tailscale identities that will use them. Aperture lists and routes only granted models.
- A ChatGPT subscription for each user, and the Codex CLI installed and able to sign in to that subscription.
Configure the Codex provider
Define a provider whose baseurl is the ChatGPT backend, with auth_mode set to passthrough.
-
Open the Aperture dashboard and go to Administration > Configuration.
-
Add a provider under the
providersmap, replacing the placeholders with your values:"providers": { "codex-oauth": { "baseurl": "https://chatgpt.com/backend-api/codex", "authorization": "bearer", "auth_mode": "passthrough", "models": ["gpt-5.3-codex"], "compatibility": { "openai_chat": true, "openai_responses": true } } }authorizationisbearer: the ChatGPT backend expects the OAuth token in theAuthorizationheader.baseurlis the ChatGPT backend, notapi.openai.com. The two endpoints accept different credentials.- No
apikeyis configured, so the provider is passthrough-only and works solely from each client's subscription token.
List each model in the
modelsarray by its exact name. Wildcards do not work:claude-opus-*matches nothing. To serve more than one model, add each full name to the array. -
Save the configuration. Aperture hot-reloads it, so no restart is required. A successful save confirms the block passed validation.
Configure the Codex CLI
Point Codex at Aperture with a custom model provider, and let it send its subscription OAuth token.
To avoid unexpected TLS issues, use http:// for the Aperture URL when configuring LLM clients. All connections remain encrypted using WireGuard, even when HTTPS is not used.
-
Sign in to your ChatGPT subscription in Codex.
-
Create or edit
~/.codex/config.toml:model = "gpt-5.3-codex" model_provider = "aperture" [model_providers.aperture] name = "Aperture" base_url = "http://<aperture-hostname>/codex" wire_api = "responses" requires_openai_auth = truerequires_openai_auth = truetells Codex to send its ChatGPT OAuth token. This is the subscription path; omit it and supplyenv_keyonly for the platform API key path.- Codex appends
/responsestobase_url, so requests arrive at Aperture as/codex/responses. Aperture strips the/codexprefix before proxying tochatgpt.com/backend-api/codex/responses.
requires_openai_auth = true with a base_url that points at the platform API does not work. The ChatGPT OAuth token lacks the api.responses.write scope the platform API requires. Use the subscription endpoint for OAuth tokens and the platform endpoint for API keys.
Verify the connection
- Send a test message in Codex.
- Open the Aperture dashboard at
http://<aperture-hostname>/ui/and confirm the request appears on the Logs page (admin only).
If a request fails with a 401, confirm Codex is signed in to the subscription and that requires_openai_auth = true is set. If the request never reaches Aperture, confirm base_url includes the /codex path segment. For more checks, refer to the passthrough troubleshooting steps.
What routes through Aperture
Only inference traffic (/responses) routes through Aperture. Codex sends OAuth login and token refresh directly to the provider, bypassing the Aperture base_url. Aperture never sees the subscription's login or refresh, only the inference requests it authenticates by Tailscale identity and forwards.
Next steps
- Grant model access: Control which models each user or group can access through Aperture.
- Set up the chat UI: Let users talk to your configured models from their browser.
- Set up LLM clients: Connect coding tools to route requests through Aperture.