Codex에 사용자 지정 API를 연결할 때 API 키, Base URL, model 이름만 채우면 끝난다고 생각하기 쉽다. 하지만 이 세 값이 서로 다른 서비스에 속하면 TOML이 정상이어도 route는 실패한다. OpenAI key를 제3자 endpoint에 보내거나, 제3자 key를 준비해 놓고 OpenAI login을 요구하면 401이 나와도 어느 시스템이 거부했는지 알 수 없다.
먼저 한 문장으로 route를 고른다.
- OpenAI Platform이 key와 API billing을 소유하면 로컬 Codex에서 OpenAI API-key login을 사용한다.
- Built-in
openaiprovider를 유지한 채 proxy, router, 적절한 region endpoint만 바꾸면openai_base_url을 사용한다. - 다른 서비스가 credential, model namespace, balance, support를 소유하면
[model_providers.<id>]를 별도로 선언한다. - 통제하는 local endpoint가 정말 인증을 요구하지 않으면 auth field 없이 custom provider를 쓴다.
아래 내용은 2026년 9월 1일 OpenAI Advanced Configuration과 Authentication을 기준으로 확인했다. Codex schema는 바뀔 수 있으므로 오래된 블로그의 field보다 현재 1차 문서를 우선해야 한다.
Route fingerprint를 먼저 만든다
설정 전 다섯 값을 한 줄에 기록한다.
| 결정 | 예시 placeholder | 증명해야 하는 것 |
|---|---|---|
| Credential issuer | OpenAI Platform / company_gateway | 계정, 인증, 청구 owner |
| Provider ID | built-in openai / 별도 ID | Codex가 선택할 provider block |
| Base URL | https://gateway.example.com/v1 | 요청을 실제 받는 서비스 |
| Model ID | EXACT_PROVIDER_MODEL_ID | 같은 provider namespace의 모델 |
| 필요한 기능 | Responses, streaming, tools | 실제 작업에서 통과해야 할 capability |

“OpenAI-compatible”이라는 문구는 request shape의 단서일 뿐이다. 같은 key를 받는지, Responses를 구현하는지, stream event와 tool call을 Codex가 기대하는 형태로 처리하는지까지 보장하지 않는다.
OpenAI API 키로 로그인하는 route
OpenAI 문서는 ChatGPT login과 API-key login을 로컬 Codex의 별도 인증 방식으로 설명한다. CLI에서는 key를 command argument에 남기지 않고 stdin으로 전달할 수 있다.
bashprintenv OPENAI_API_KEY | codex login --with-api-key codex login status
이 route의 사용량은 OpenAI Platform account와 project에 속하며 API 요금으로 청구된다. ChatGPT plan의 included usage가 아니다. Codex cloud는 ChatGPT login이 필요하므로 API key만으로 cloud 기능까지 같은 계약이 되지 않는다.
인증 cache는 ~/.codex/auth.json 또는 OS credential store에 저장될 수 있다. File storage를 쓴다면 auth.json은 password처럼 다뤄야 한다. Git에 commit하거나 issue, chat, support ticket에 붙이지 않는다. 현재 방식은 파일 내용을 복사하지 말고 codex login status로 확인한다.
청구 경로 자체를 결정하지 못했다면 먼저 Codex API 키와 구독 선택을 읽는 편이 안전하다.
Built-in OpenAI의 Base URL만 바꾸는 route
OpenAI auth와 built-in provider를 유지하면서 적절한 proxy나 region endpoint를 통과하려면 user config에 전용 key를 둔다.
toml# ~/.codex/config.toml openai_base_url = "https://proxy.example.com/v1"
이 경우 [model_providers.openai]를 만들지 않는다. openai, ollama, lmstudio는 reserved built-in provider ID라 같은 이름의 custom block으로 대체할 수 없다.
openai_base_url도 임의 gateway의 호환성을 증명하지 않는다. Gateway가 자체 token, 자체 balance, 자체 model alias와 support를 제공한다면 별도 provider contract다. OpenAI login에 섞기보다 새 provider ID로 분리해야 401, model not found, billing 문제의 owner가 보인다.
자체 API 키를 쓰는 custom provider
Provider routing은 user-level ~/.codex/config.toml에 둔다.
tomlmodel = "EXACT_PROVIDER_MODEL_ID" model_provider = "company_gateway" [model_providers.company_gateway] name = "Company gateway" base_url = "https://gateway.example.com/v1" env_key = "COMPANY_GATEWAY_API_KEY" wire_api = "responses"
Secret은 TOML이 아니라 Codex를 시작하는 environment에 둔다.
bashexport COMPANY_GATEWAY_API_KEY="replace-with-provider-key"
env_key는 secret 값이 아니라 환경 변수 이름이다. Terminal에서 export한 뒤 다른 환경의 IDE나 desktop app을 실행하면 해당 process가 variable을 상속하지 못할 수 있다. 값은 출력하지 말고 존재만 확인한다.
bashif [ -n "${COMPANY_GATEWAY_API_KEY:-}" ]; then echo "provider key is available" else echo "provider key is missing" fi
모든 Base URL에 /v1을 붙이는 규칙은 없다. Provider의 현재 문서가 요구하는 root와 같은 account에서 보이는 exact model ID를 사용한다.
한 provider에는 한 인증 source만 둔다
Alternative provider 인증 문서는 다음을 구분한다.
requires_openai_auth = true는 OpenAI authentication을 사용하며env_key를 무시한다. OpenAI auth를 명시적으로 받는 LLM proxy에 맞는다.env_key = "PROVIDER_VARIABLE"은 provider 자체 API key를 named environment variable에서 읽는다.- 둘 다 없으면 Codex는 인증이 필요 없는 endpoint로 간주한다. 이는 통제된 local service에만 적합하다.
짧은 수명의 bearer token이 필요한 enterprise gateway는 [model_providers.<id>.auth] command를 사용할 수 있다. 이 auth command는 env_key, requires_openai_auth, experimental bearer token과 함께 쓰면 안 된다. 인증 source를 여러 개 두면 fallback이 아니라 401의 원인을 숨긴다.
Project .codex/config.toml에 두면 왜 무시되는가
Trusted project도 machine-level provider와 auth를 redirect할 수 없다. OpenAI의 project config 문서는 project layer에서 다음 key가 무시된다고 설명한다.
openai_base_urlmodel_providermodel_providers
이 값은 ~/.codex/config.toml로 옮긴다. 이는 parse error가 아니라 repository가 사용자의 code context와 credential을 다른 endpoint로 조용히 보낼 수 없게 하는 security boundary다.
User config도 적용되지 않는다면 실제 launch command, CLI --config, 선택한 profile을 확인한다. Precedence는 허용된 값의 승자를 정하지만, 제한된 project key를 허용해 주지는 않는다.
/v1/models보다 같은 route의 실제 요청을 본다
Provider block이 parse되었다고 end-to-end가 성공한 것은 아니다. /v1/models가 200이어도 list endpoint만 확인했을 뿐 Responses, auth, streaming, tools는 아직 모른다.

- User config를 backup하고 새 provider block을 최소로 줄인다.
- Provider ID, Base URL, model ID, wire API, credential issuer가 한 서비스를 가리키는지 확인한다.
- Environment variable이 보이는 같은 process에서 Codex를 시작한다.
- Repository나 개인정보가 없는 짧은 작업으로 정확히
ROUTE_OK만 답하게 한다. - Text 성공 뒤 실제 업무에 필요한 streaming, tool call, long context, web search를 각각 검증한다.
Text 한 번 성공했다고 “완전 호환”이라고 부르면 안 된다. 요청이 의도한 provider에 도달한 뒤에는 config layer를 계속 바꿔도 account access나 adapter capability 문제를 고칠 수 없다.
결과가 다음 owner를 알려 준다
| 관찰 결과 | 다음 owner | 조치 |
|---|---|---|
| 이전 provider가 계속 사용됨 | Config layer, profile, launch flag | User config와 실제 실행 조건을 대조 |
| Environment variable 없음 | Process environment | Codex 시작 process에 variable을 전달하고 secret은 출력하지 않음 |
401 / 403 | Credential, account, auth scheme | Key 발급자에게 scope와 상태 확인 |
404 / 405 | Base URL, path, wire API | Provider의 현재 endpoint contract와 비교 |
| Model not found | Model mapping, entitlement | 같은 provider account에서 보이는 exact ID 사용 |
| Text 성공, stream/tool 실패 | Provider capability, adapter | 최소 failing test를 남기고 호환 범위를 축소 |
| Platform 비용만 늘어남 | Login, billing route | codex login status와 Codex token usage 확인 |
지원 요청에는 Codex version, OS, CLI/IDE/desktop surface, provider ID, Base URL hostname, model ID, wire_api, 전체 error text, status, request ID, timestamp만 남긴다. API key, Authorization header, auth.json, private code, customer data는 제거한다.
설정 완료는 읽힌 layer, credential issuer, 요청 수신 Base URL, model namespace, 실패 후 다음 owner를 설명할 수 있는 상태다. 하나라도 모르면 field를 더 넣지 말고 provider 하나, auth source 하나, 민감하지 않은 request 하나로 돌아간다. 작은 route는 진단할 수 있지만 서로 다른 service의 예제를 합친 “만능 config.toml”은 진단할 수 없다.



