# Codex Custom Provider 설정: API 키와 Base URL 연결법

> 키 발급자와 실제 요청 수신자를 먼저 맞추면 API-key 로그인, openai_base_url, 별도 provider 중 필요한 설정과 실패 후 확인할 owner가 선명해집니다.

- URL: https://blog.laozhang.ai/ko/posts/codex-config-toml
- Published: 2026-08-04
- Updated: 2026-09-01
- Author: LaoZhang AI Team (https://blog.laozhang.ai/ko/about)
- Topic: 개발 도구·에이전트
- Tags: OpenAI Codex, Codex API 키, Codex Base URL, Custom Provider, config.toml

---
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 `openai` provider를 유지한 채 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](https://learn.chatgpt.com/docs/config-file/config-advanced#custom-model-providers)과 [Authentication](https://learn.chatgpt.com/docs/auth)을 기준으로 확인했다. 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 |

![Codex의 OpenAI API-key 로그인, Base URL 변경, 별도 provider와 사용자 설정 경계를 정리한 경로](https://blog.laozhang.ai/posts/ko/codex-config-toml/img/route-and-auth.webp)

“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으로 전달할 수 있다.

```bash
printenv 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 키와 구독 선택](https://blog.laozhang.ai/ko/posts/codex-api-key-vs-subscription)을 읽는 편이 안전하다.

## 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`에 둔다.

```toml
model = "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에 둔다.

```bash
export COMPANY_GATEWAY_API_KEY="replace-with-provider-key"
```

`env_key`는 secret 값이 아니라 **환경 변수 이름**이다. Terminal에서 export한 뒤 다른 환경의 IDE나 desktop app을 실행하면 해당 process가 variable을 상속하지 못할 수 있다. 값은 출력하지 말고 존재만 확인한다.

```bash
if [ -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 인증 문서](https://learn.chatgpt.com/docs/auth#alternative-model-providers)는 다음을 구분한다.

1. `requires_openai_auth = true`는 OpenAI authentication을 사용하며 `env_key`를 무시한다. OpenAI auth를 명시적으로 받는 LLM proxy에 맞는다.
2. `env_key = "PROVIDER_VARIABLE"`은 provider 자체 API key를 named environment variable에서 읽는다.
3. 둘 다 없으면 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 문서](https://learn.chatgpt.com/docs/config-file/config-advanced#project-config-files-codexconfigtoml)는 project layer에서 다음 key가 무시된다고 설명한다.

- `openai_base_url`
- `model_provider`
- `model_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는 아직 모른다.

![같은 Codex route의 최소 검증 결과로 config, credential, Base URL, model, provider capability owner를 찾는 진단표](https://blog.laozhang.ai/posts/ko/codex-config-toml/img/verification-and-errors.webp)

1. User config를 backup하고 새 provider block을 최소로 줄인다.
2. Provider ID, Base URL, model ID, wire API, credential issuer가 한 서비스를 가리키는지 확인한다.
3. Environment variable이 보이는 같은 process에서 Codex를 시작한다.
4. Repository나 개인정보가 없는 짧은 작업으로 정확히 `ROUTE_OK`만 답하게 한다.
5. 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](https://blog.laozhang.ai/ko/posts/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”은 진단할 수 없다.

## 참고 자료

이 글이 링크한 외부 페이지를 본문에 나온 순서대로 정리했습니다. 마지막 업데이트: 2026-09-01.

- [Advanced Configuration](https://learn.chatgpt.com/docs/config-file/config-advanced) (learn.chatgpt.com)
- [Authentication](https://learn.chatgpt.com/docs/auth) (learn.chatgpt.com)
