Status 401Authentication (401)Codex CLICC Switch

Fix Codex "unexpected status 401 Unauthorized"

Error message
unexpected status 401 Unauthorized: {"type":"error","error":{"type":"authentication_error","message":"Missing or invalid API key"}}, url: https://www.ccsub.net/api/v1/responses

Codex CLI or Codex Desktop failing with unexpected status 401 Unauthorized against CCSub? Read the url at the end of the error first. Then pin the key with a custom model provider and env_key so Codex can't pick up the wrong credential.

Fix it in 3 steps

  1. 1

    Read the url at the end of the error

    If it says https://www.ccsub.net/api/v1/responses, the request reached CCSub and the key was rejected. If it points anywhere else (an OpenAI or ChatGPT domain), your base URL isn't being applied — fix the config before touching the key.

  2. 2

    Define a custom provider in config.toml

    At the top of ~/.codex/config.toml set model_provider = "ccsub", then add a [model_providers.ccsub] table with base_url = "https://www.ccsub.net/api/v1", env_key = "OPENAI_API_KEY" and wire_api = "responses". Codex will then read the key only from OPENAI_API_KEY.

  3. 3

    Export the variable where Codex runs and verify the key

    Run export OPENAI_API_KEY="sk-..." and start codex from that same terminal. Copy the key again from API Keys in the dashboard and make sure it's enabled. Codex Desktop launched from the Dock won't see variables from ~/.zshrc, so test from a terminal first.

Other forms of the same error

  • unexpected status 401 Unauthorized: {"type":"error","error":{"type":"authentication_error","message":"Invalid or disabled API key"}}, url: https://www.ccsub.net/api/v1/responses
  • Missing environment variable: `OPENAI_API_KEY`.

Read the url first, then the message

Codex formats HTTP errors as unexpected status 401 Unauthorized: <response body>, url: <request URL>. That trailing url tells you where the request actually went:

  • https://www.ccsub.net/api/v1/responses — the request reached CCSub and the key was refused. Read the message in the body.
  • Any other host — Codex isn't using your CCSub settings and is still talking to its default provider. Swapping keys won't help; fix the config file.

CCSub only has two 401 messages. Missing or invalid API key means the request had no key or the value didn't start with sk- (a ChatGPT login token doesn't). Invalid or disabled API key means it carried an sk- value that doesn't exist, was truncated, or was disabled or deleted in the dashboard.

A config.toml that works with CCSub

Codex's configuration reference supports custom model providers: base_url is the endpoint, env_key names the environment variable that holds the API key, and wire_api accepts responses (the only supported value). For CCSub:

# ~/.codex/config.toml
model = "gpt-5.5"
model_provider = "ccsub"

[model_providers.ccsub]
name = "CCSub"
base_url = "https://www.ccsub.net/api/v1"
env_key = "OPENAI_API_KEY"
wire_api = "responses"

Then:

export OPENAI_API_KEY="sk-your-key"
codex

env_key holds the name of an environment variable, not the key itself. This guide uses OPENAI_API_KEY to match the install docs. If that variable is already taken by another service, rename it in both places (env_key and the export line), for example to CCSUB_API_KEY, so you always know which credential Codex used. Set model to any model ID from the CCSub model list.

Four mistakes that cause this

Top-level keys placed under a table. In TOML, every key after a [model_providers.ccsub] header belongs to that table. If you append model_provider = "ccsub" at the bottom of the file, it becomes a field of the provider table, Codex never sees it, and it falls back to the default provider — which is why the url in the error isn't ccsub.net. Keep model, model_provider, and openai_base_url at the very top, before any [...] header. The Codex issue tracker has a case where openai_base_url was ignored for exactly this reason.

The variable exists, but not in the Codex process. export only applies to the current shell and programs started from it. Codex Desktop opened from the Dock or Start menu, or an editor extension, usually can't see variables from ~/.zshrc. You'll get Missing environment variable or a 401. Prove the key works by exporting it and running codex in a terminal, then sort out the desktop app's environment. On Windows, after [System.Environment]::SetEnvironmentVariable, close every terminal and Codex window before trying again.

A switcher tool rewrote your config. Tools like CC Switch rewrite ~/.codex/config.toml and auth.json when you switch providers. Edit by hand and then click switch in the tool, and your changes can be overwritten. Pick one way of managing the config and stick to it.

The key is truncated or disabled. A CCSub key is sk- plus 64 hex characters, 67 in total. The API Keys page keeps the full key so you can copy it again any time, and a disabled key can be re-enabled there. To test the key without Codex in the way (one tiny billable request):

curl -sS -w '\n%{http_code}\n' https://www.ccsub.net/api/v1/responses \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "content-type: application/json" \
  -d '{"model":"gpt-5.5","input":"hi"}'

A 200 means the key is good and the issue is your Codex config. A 401 means try a different key.

FAQ

I exported OPENAI_API_KEY. Why do I still get 401?

Without a custom provider in config.toml, Codex uses the built-in openai provider, which works off the credentials saved by codex login (stored in ~/.codex/auth.json by default), so it may not use the variable you exported. If you ever signed in with a ChatGPT account, that login is what gets sent instead of your CCSub key. With model_provider = "ccsub" and env_key set as shown above, Codex only reads the key from OPENAI_API_KEY.

Does OPENAI_BASE_URL still work?

Codex has deprecated the OPENAI_BASE_URL environment variable in favor of a top-level openai_base_url key in config.toml. The old variable still works but prints a warning. For CCSub, the custom provider block above is cleaner because the URL and the key source live in one place.

What does "Missing environment variable" mean?

It's a local Codex error: the variable named in env_key is unset or empty in the Codex process, so nothing was sent yet. Check the spelling matches, that you exported it in the same shell, and that the desktop app or IDE extension is launched from an environment that has it.

Are 401 responses billed?

No. Authentication fails before anything is forwarded to a model.

Still stuck?

New to CCSub?

Sign up, create an API key in the dashboard, and paste it into Claude Code, Codex CLI or your editor. You pay for what you use.