Please document Azure setup end-to-end: deployment name vs model, `base_url` (with `/openai`), `api-version`, `wire_api` (`responses` vs `chat.completions`), and Entra ID (Device Code & Client Credentials) token plumbing
What is the type of issue?
Documentation is missing
What is the issue?
Summary
The Codex CLI README has partial Azure guidance, but several details are unclear or scattered. We need a single, explicit section that shows exactly how to configure and run Codex against Azure OpenAI with:
- Entra ID (AAD) tokens (both Device Code and Client Credentials flows), and
- Azure API keys (if supported by the CLI),
including the correct URL path shape, how to set api-version, how to select the wire API (responses vs chat.completions), and the fact that “model” must be the Azure deployment name.
This is a request for documentation changes only.
Pain points / why this matters
- It’s easy to misconfigure
base_url(missing the/openaisegment) and get 404s. - It’s not obvious that
modelmust be the Azure deployment name (not the base model alias). - It’s unclear what env var the Azure provider reads and whether the value must be an API key or a raw AAD access token—and whether to include the
"Bearer "prefix. - The docs don’t explicitly show how to choose between
responsesandchat.completionson Azure (and how the final path differs). - CLI flag surface:
--providerisn’t accepted, but examples floating around still show it; the reliable way is profiles. - Troubleshooting guidance (401 vs 404, logging location, printing effective config/URL) would save a lot of time.
Requested documentation additions/clarifications
- Minimal working config for Azure (TOML) Include a canonical snippet that uses profiles and the Azure provider:
# ~/.codex/config.toml
model_provider = "azure"
model = "<AZURE_DEPLOYMENT_NAME>" # <- Azure deployment name, not base model
[model_providers.azure]
name = "Azure"
# IMPORTANT: include /openai; Codex appends /deployments/{model}/...
base_url = "https://<YOUR_AZURE_OPENAI_ENDPOINT>/openai"
query_params = { api-version = "2025-04-01-preview" } # or a supported version
wire_api = "responses" # or "chat.completions" (see below)
env_key = "AZURE_OPENAI_API_KEY"
[profiles.azure]
model_provider = "azure"
model = "<AZURE_DEPLOYMENT_NAME>"
- Explicit path shapes built by Codex Please document the exact paths Codex calls for each wire:
-
wire_api = "responses"→POST https://<...>/openai/deployments/<DEPLOYMENT>/responses?api-version=... -
wire_api = "chat.completions"→POST https://<...>/openai/deployments/<DEPLOYMENT>/chat/completions?api-version=...
Call out that base_url must end with /openai (not just the resource root).
-
“Model” vs Azure deployment name State plainly that
modelmust be the Azure deployment name. If there’s a CLI validation step or error message you can add, great—otherwise, the doc should warn that using a base model alias will cause a 404. -
Auth variables and semantics
- Which env var(s) does the Azure provider read? (e.g.,
AZURE_OPENAI_API_KEY; does it fall back toOPENAI_API_KEY?) - If the value is an AAD access token, should the env var contain the raw JWT or include the
"Bearer "prefix? (Please specify; examples below assume raw JWT, no prefix.) - If API keys are supported: does the provider expect the Azure resource key in the same env var? Does the CLI send it as
Authorization: Bearer <value>orapi-key: <value>? Please document the exact header behavior for both tokens and keys.
- Which env var(s) does the Azure provider read? (e.g.,
-
End-to-end examples for Entra ID (AAD)
A. Client Credentials flow (no user interaction)
# 1) mint an AAD access token (raw JWT, no "Bearer ")
export AZURE_OPENAI_API_KEY="$(python - <<'PY'
from azure.identity import ClientSecretCredential
cred = ClientSecretCredential(
tenant_id="<TENANT_ID>",
client_id="<CLIENT_ID>",
client_secret="<CLIENT_SECRET>",
)
print(cred.get_token("https://cognitiveservices.azure.com/.default").token)
PY
)"
# 2) run Codex with Azure profile and deployment name
codex --profile azure -m "<AZURE_DEPLOYMENT_NAME>" "hello from client credentials"
B. Device Code flow (interactive)
# 1) mint a user token via Device Code (raw JWT, no "Bearer ")
export AZURE_OPENAI_API_KEY="$(python - <<'PY'
from azure.identity import DeviceCodeCredential
cred = DeviceCodeCredential(
tenant_id="<TENANT_ID>",
client_id="<PUBLIC_CLIENT_ID>" # device-code capable app reg
)
print(cred.get_token("https://cognitiveservices.azure.com/.default").token)
PY
)"
# 2) run Codex
codex --profile azure -m "<AZURE_DEPLOYMENT_NAME>" "hello from device code"
Please also note in the docs: token length will usually be ~1200–2000 bytes; a length of 0 indicates the shell var is empty.
-
Choosing the wire (
responsesvschat.completions)- Which wire is the default on Azure?
- If both are supported, recommend a default and document when users should switch.
- Provide a quick troubleshooting matrix for 404s when the wrong wire is configured.
-
api-versionguidance- Show how to set it via
query_params = { api-version = "..." }. - List known-good versions for Azure’s Responses and Chat Completions wires (or link to Azure’s version matrix), and clarify what the CLI expects.
- Show how to set it via
-
CLI flags & config precedence
- Please remove or correct references to
--providerif it’s not supported; show--profilein all examples. - Document the precedence between config vs env vars vs auth files, and how to disable ChatGPT account fallback when targeting Azure.
- Please remove or correct references to
-
Troubleshooting section
- 401 typically → token/permission/audience issue.
-
404 typically → wrong deployment name, wrong path shape (missing
/openai), unsupported wire orapi-version. - Where do logs go? (e.g.,
~/.codex/log/codex-tui.log). - A tip to print the final resolved URL (path + query) would be ideal; if there’s a flag to dump the effective config or HTTP target, please document it.
-
(Nice-to-have) Feature request note If the Azure provider could optionally run MSAL directly (Device Code / Client Credentials) and refresh the token, that would eliminate the external scripting step. If not planned, explicitly state “no built-in MSAL; bring your own token via env var.”
Expected outcome
A concise, authoritative “Using Codex with Azure OpenAI” doc section that:
- Provides copy-pasteable TOML and shell examples for Device Code and Client Credentials,
- Clearly distinguishes deployment name vs base model,
- Disambiguates the URL shape, wire, and api-version knobs, and
- Explains env var semantics for AAD tokens and/or API keys.
This will prevent common 404/401 misconfigurations and reduce support load.
Where did you find it?
No response
Fixed by https://github.com/openai/codex/pull/2162
Im also very interested in these changes to the documentation. Especially Entra ID part. I dont see how #2162 fixed the docs?
Yeah, this doesn't look fixed. That change only changed one Rust file.
@kentyman23, I agree. I'm going to reopen this because I think additional documentation is needed in this area.