codex icon indicating copy to clipboard operation
codex copied to clipboard

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

Open santiago-afonso opened this issue 5 months ago • 4 comments

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 /openai segment) and get 404s.
  • It’s not obvious that model must 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 responses and chat.completions on Azure (and how the final path differs).
  • CLI flag surface: --provider isn’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

  1. 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>"
  1. 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).

  1. “Model” vs Azure deployment name State plainly that model must 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.

  2. Auth variables and semantics

    • Which env var(s) does the Azure provider read? (e.g., AZURE_OPENAI_API_KEY; does it fall back to OPENAI_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> or api-key: <value>? Please document the exact header behavior for both tokens and keys.
  3. 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.

  1. Choosing the wire (responses vs chat.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.
  2. api-version guidance

    • 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.
  3. CLI flags & config precedence

    • Please remove or correct references to --provider if it’s not supported; show --profile in all examples.
    • Document the precedence between config vs env vars vs auth files, and how to disable ChatGPT account fallback when targeting Azure.
  4. Troubleshooting section

    • 401 typically → token/permission/audience issue.
    • 404 typically → wrong deployment name, wrong path shape (missing /openai), unsupported wire or api-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.
  5. (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

santiago-afonso avatar Aug 08 '25 16:08 santiago-afonso

Fixed by https://github.com/openai/codex/pull/2162

seratch avatar Aug 12 '25 04:08 seratch

Im also very interested in these changes to the documentation. Especially Entra ID part. I dont see how #2162 fixed the docs?

bahtman avatar Sep 20 '25 09:09 bahtman

Yeah, this doesn't look fixed. That change only changed one Rust file.

kentyman23 avatar Dec 03 '25 20:12 kentyman23

@kentyman23, I agree. I'm going to reopen this because I think additional documentation is needed in this area.

etraut-openai avatar Dec 03 '25 21:12 etraut-openai