Route a ChatGPT subscription through Aperture

Last validated:

Aperture by Tailscale is currently in beta.

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:

EndpointCredentialBilling
chatgpt.com/backend-api/codexChatGPT OAuth tokenChatGPT subscription (Plus, Pro, Team, Enterprise)
api.openai.com/v1API key with the api.responses.write scopePlatform 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.

  1. Open the Aperture dashboard and go to Administration > Configuration.

  2. Add a provider under the providers map, 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
        }
      }
    }
    
    • authorization is bearer: the ChatGPT backend expects the OAuth token in the Authorization header.
    • baseurl is the ChatGPT backend, not api.openai.com. The two endpoints accept different credentials.
    • No apikey is configured, so the provider is passthrough-only and works solely from each client's subscription token.

    List each model in the models array 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.

  3. 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.

  1. Sign in to your ChatGPT subscription in Codex.

  2. 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 = true
    
    • requires_openai_auth = true tells Codex to send its ChatGPT OAuth token. This is the subscription path; omit it and supply env_key only for the platform API key path.
    • Codex appends /responses to base_url, so requests arrive at Aperture as /codex/responses. Aperture strips the /codex prefix before proxying to chatgpt.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

  1. Send a test message in Codex.
  2. 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