API-ключ Codex — не просто строка. Он определяет, от чьего имени тарифицируются запросы, к каким моделям есть доступ и насколько велик ущерб при утечке. Частые 401 связаны не с недействительным ключом, а с несовпадением имени переменной, переписанным заголовком, неверным уровнем конфигурации или старыми учётными данными в локальном кэше.

Статья описывает типы ключей, создание, переменные окружения и файл конфигурации, profiles, ротацию, минимальные права, CI и диагностику 401 — в порядке, который можно повторить напрямую. Команды и параметры сверяйте с текущей версией Codex и документацией используемого шлюза.

Примечание: OpenAI, Codex и ChatGPT — товарные знаки или зарегистрированные товарные знаки OpenAI. Статья носит технический характер и не подразумевает аффилированности с OpenAI. Права ключей, доступные интерфейсы и тарификация определяются официальной документацией платформ и страницами сайта.

1. Сначала разделите три типа ключей и два хранилища

Учётные данные Codex легко перепутать; разделите их по назначению:

Название Типичное использование Где хранится Замечания
OpenAI Platform API Key Вход через codex login --with-api-key auth.json или системное хранилище Тарификация по стандартным ставкам API
CODEX_API_KEY codex exec, SDK и другие разовые запуски Только окружение текущего процесса Не пишется на диск, подходит для CI
Ключ пользовательского provider Через env_key указывает на переменную Окружение оболочки или сервис секретов Часто используется в командном шлюзе, удобен для лимитов

Первое хранилище — «учётные данные входа», им управляет cli_auth_credentials_store: file пишет auth.json в CODEX_HOME, keyring использует системное хранилище, auto сначала пробует хранилище и откатывается к файлу, ephemeral держит данные только в памяти процесса. Второе хранилище — «ключ provider», задаваемый именем переменной в env_key; Codex читает её при каждом запросе. Важно: env_key — это только имя переменной, а не сама переменная.

CODEX_HOME по умолчанию ~/.codex, его можно перенести в контролируемый каталог. OPENAI_API_KEY — источник, который читает команда входа; CODEX_API_KEY — разовые учётные данные неинтерактивного запуска. Названия похожи, назначение разное.

2. Создание ключа: пять шагов

  1. Откройте ZSQH AI Gateway или используемую платформу, зарегистрируйтесь и войдите в консоль.
  2. Перейдите на страницу «API-ключи» и создайте ключ; в названии укажите среду и назначение, например codex-work-mac.
  3. Задайте лимит и срок действия. Тестовому ключу сначала дайте небольшой лимит и скорректируйте после реального расхода.
  4. Если платформа поддерживает белый список моделей или область проекта, отметьте только те модели, которые нужны Codex.
  5. Скопируйте ключ целиком и сразу сохраните в менеджере паролей или сервисе секретов. Большинство консолей показывают его только один раз.

Ключ часто начинается с sk-, но префикс не доказывает подлинность и ничего не говорит о правах. При копировании проверьте пробелы по краям, переводы строки и лишние кавычки — это частая причина 401. После создания проверьте минимальным запросом и только потом раздавайте команде.

3. Как сочетаются переменные окружения и config.toml

Рекомендуемый подход: в конфигурации только имя переменной, реальный ключ — в окружении или инструменте управления секретами. Пример ~/.codex/config.toml:

# ~/.codex/config.toml
model = "your-model-id"
model_provider = "zsqh"

[model_providers.zsqh]
name = "ZSQH AI Gateway"
base_url = "https://ai.zhongshangqihang.com/v1"
wire_api = "responses"
env_key = "ZSQH_API_KEY"
env_key_instructions = "Создайте ключ в консоли шлюза и экспортируйте его как переменную окружения"

Затем экспортируйте ключ в той же оболочке, из которой запускается Codex:

export ZSQH_API_KEY="sk-ваш-ключ"

В macOS и Linux эту строку можно положить в приватный файл вроде ~/.zshrc.local, а основной файл конфигурации оставить со ссылкой на переменную. В Windows PowerShell используйте $env:ZSQH_API_KEY="sk-ваш-ключ". Процессы, запущенные из Dock, IDE или настольного приложения, могут не видеть переменные из конфигурации оболочки; в этом случае задавайте их в стартовом скрипте или системных переменных.

Если шлюз требует пользовательский заголовок, вместо env_key можно использовать env_http_headers = { "X-API-Key" = "ZSQH_API_KEY" } и настроить локальный каталог моделей. Если ключ динамически выдаётся Vault, KMS или похожим инструментом, токен можно получать через command в [model_providers.zsqh.auth], но не одновременно с env_key. Поле experimental_bearer_token позволяет вписать ключ напрямую, но официально не рекомендуется; в командной среде его лучше избегать.

Можно также использовать вход: printenv OPENAI_API_KEY | codex login --with-api-key — учётные данные попадут в auth.json или хранилище; очистка выполняется через codex logout. Для командного шлюза предпочтительнее env_key: лимиты, права на модели и отзыв управляются централизованно на стороне шлюза.

4. Несколько конфигураций и profiles

Рекомендуется как минимум три набора учётных данных: личный повседневный, проектный и автоматизированный. У них разные лимиты, права и циклы ротации; смешивание затрудняет и учёт расхода, и диагностику.

В новых версиях Codex profile вынесен в отдельный файл. В основной конфигурации определите два provider с разными переменными:

# ~/.codex/config.toml
model = "your-model-id"
model_provider = "zsqh_work"

[model_providers.zsqh_work]
base_url = "https://ai.zhongshangqihang.com/v1"
wire_api = "responses"
env_key = "ZSQH_WORK_KEY"

[model_providers.zsqh_test]
base_url = "https://ai.zhongshangqihang.com/v1"
wire_api = "responses"
env_key = "ZSQH_TEST_KEY"

Затем создайте ~/.codex/test.config.toml, где укажите только переопределяемые ключи верхнего уровня:

model = "your-test-model-id"
model_provider = "zsqh_test"

Переключение выполняется командой codex --profile test. Учтите: начиная с версии 0.134.0 старые таблицы [profiles.xxx] и запись profile = "..." верхнего уровня больше не читаются; в файле profile не нужно снова вкладывать [profiles.xxx] — используйте ключи верхнего уровня. Старые версии могут принимать прежний синтаксис; перед обновлением смотрите примечания к версии.

.codex/config.toml в доверенном проекте подходит только для несекретных соглашений; model_provider, model_providers и profile из него игнорируются, и ключ туда тоже писать и коммитить нельзя.

5. Ротация ключей: когда и как

Цель ротации — не формальность, а сокращение окна действия после утечки. Поводом служат уход сотрудника, потеря устройства, подозрение на утечку, требование поставщика и фиксированный цикл, например каждые 90 дней.

  1. Создайте в консоли новый ключ с датой в названии, например codex-prod-2026-10.
  2. Сначала запишите новый ключ в инструмент управления секретами или переменную окружения, старый пока сохраните.
  3. Проверьте оба ключа через codex exec и минимальный запрос: модель, лимит и права должны работать.
  4. Посмотрите журнал расхода старого ключа и убедитесь, что забытых скриптов или сотрудников не осталось.
  5. Отключите старый ключ и наблюдайте долю ошибок и неудачные запросы ещё один-два дня.
  6. Зафиксируйте время ротации, ответственного и область влияния для передачи и аудита.

Не выполняйте ротацию в пик нагрузки. Параллельная работа двух ключей безопаснее схемы «удалить и создать». Если используется только вход, после ротации выполните codex logout и войдите заново, чтобы в auth.json не остались старые данные. auth.json нужно защищать как пароль и не синхронизировать с публичными облачными дисками или репозиториями.

6. Минимальные права и защита от утечек

  • Один ключ на человека, при необходимости дополнительно по средам; для CI отдельный ключ с отдельным лимитом.
  • Задайте ключу срок действия, бюджет и лимит параллельности; открывайте только нужные модели.
  • Если платформа поддерживает белый список IP, ограничьте офисной сетью или выходом runner; если нет — полагайтесь на лимиты и оповещения.
  • В корпоративной среде можно принудительно задать forced_login_method = "api" или "chatgpt", чтобы сотрудники не смешивали учётные данные.
  • На личной машине предпочтителен cli_auth_credentials_store = "keyring"; на общей машине или в CI — ephemeral, чтобы меньше писалось на диск.
  • .gitignore должен покрывать .env, .env.*, auth.json, *.pem и подобные файлы; перед коммитом проверяйте шаблон sk- через secret scanning или pre-commit hook.
  • Не вписывайте ключ по умолчанию в код, не отлаживайте через echo $ZSQH_API_KEY, маскируйте заголовок Authorization в журналах.

При подтверждённой утечке порядок такой: сначала отключите или удалите ключ, затем создайте новый, после чего проверьте журнал расхода и историю репозитория. Удалить файл недостаточно — старый ключ мог уже быть скопирован в другое место.

7. CI и неинтерактивное использование

Принцип CI: «ключ не попадает в код, образ и журналы».

  • Для разового запуска используйте CODEX_API_KEY=<key> codex exec --json "...", подставляя значение только перед командой, а не на уровне переменных задания.
  • В GitHub Actions предпочтителен официальный Action Codex; не вставляйте ключ прямо в шаг shell.
  • В CI используйте отдельный ключ с низким лимитом и узкими правами, доступный только на защищённых ветках или в доверенных workflow.
  • Используйте --ephemeral, чтобы файлы сессии не писались на диск; вне Git-репозитория при необходимости добавьте --skip-git-repo-check.
  • Не используйте управляемые учётные данные ChatGPT в публичных репозиториях и на недоверенных runner.

8. Диагностика 401: порядок проверки

401 означает ошибку аутентификации, но не обязательно неверный ключ. Проверяйте по порядку:

  1. Выполните codex login status и определите фактически действующий способ входа.
  2. Убедитесь, что имя переменной в env_key написано без ошибок и переменная непустая в текущем процессе; проверяйте длину, не печатая значение целиком.
  3. Определите, из какого окружения запущен Codex. Встроенный терминал IDE, Docker, systemd и launchd могут не наследовать переменные оболочки.
  4. Заново скопируйте ключ из консоли, исключив пробелы, переводы строки и кавычки.
  5. Если используются учётные данные входа, выполните codex logout и войдите снова, чтобы исключить остатки в auth.json.
  6. Проверьте, не конфликтует ли forced_login_method с текущим типом учётных данных; при несовпадении Codex может завершиться или отклонить запрос.
  7. Проверьте, не истёк ли ключ, не отключён ли он, есть ли баланс и права на модель.
  8. Убедитесь, что Base URL и путь /v1 верны, а прокси не удаляет и не переписывает Authorization; при необходимости сверьтесь с журналом шлюза.

Частые ошибки:

Симптом Частая причина Что делать
401 — ошибка аутентификации Переменная не экспортирована, имя не совпадает, учётные данные истекли Сверить env_key; переоткрыть терминал; войти заново
403 Forbidden Нет прав на модель, ограничение IP, заморожен лимит Проверить права и белый список в консоли
404 Not Found Лишний или пропущенный /v1, неверный путь Сверить адрес и доступные интерфейсы по частям
429 Too Many Requests Превышена параллельность или лимит Снизить параллельность, проверить лимит ключа
model not found Неверный идентификатор модели Скопировать точный идентификатор со страницы цен

Частые вопросы

API-ключ Codex и подписка ChatGPT — это одно и то же?

Нет. Подписка ChatGPT относится к веб- и клиентским продуктам; Codex может входить через аккаунт или работать по API Key с оплатой по факту. Лимиты, счета и объём прав различаются, поэтому в команде их нужно учитывать раздельно.

Как связаны env_key и OPENAI_API_KEY?

env_key — параметр конфигурации, значением которого является имя переменной окружения; OPENAI_API_KEY — одно из распространённых имён и источник для codex login --with-api-key. Можно указать env_key = "OPENAI_API_KEY", но лучше дать шлюзу отдельное имя, чтобы не смешивать с учётными данными входа.

Можно ли вписать ключ прямо в config.toml?

Не рекомендуется. Открытый ключ легко утекает вместе с резервной копией конфигурации, скриншотом или репозиторием. Используйте env_key со ссылкой на переменную или [model_providers.xxx.auth] с внешней командой получения токена.

Нужно ли останавливать сервис при ротации ключа?

Нет. Создайте и проверьте новый ключ, переключите конфигурацию, затем отключите старый — параллельная работа двух ключей позволяет избежать обрыва запросов.

Почему codex login status в порядке, а запросы всё равно дают 401?

Статус входа показывает лишь наличие локальных учётных данных и не подтверждает работоспособность ключа пользовательского provider. Проверьте переменную env_key, Base URL, баланс шлюза и права на модель; если запрос идёт через прокси, проверьте, не переписываются ли заголовки.

Что дальше

Если ключа ещё нет, создайте тестовый ключ с небольшим лимитом через страницу регистрации и настройте его по порядку из статьи. Модели, лимиты и способ тарификации смотрите на странице «Модели и цены»; цены меняются вслед за версиями моделей и политикой upstream, ориентируйтесь на актуальную информацию страницы.

Читайте также: