These notes underpin PLAN.md. They are the raw evidence a reviewer (human or cloud agent) needs to avoid re-researching from scratch. All facts here were verified against official documentation or source code in April 2026.
The mechanism. [model_providers.<id>.auth] is a first-class table in Codex's config schema. It accepts command, args, cwd, timeout_ms (default 5000), refresh_interval_ms (default 300000). The command must print the bearer token to stdout; Codex trims whitespace, rejects empty output, and proactively refreshes at refresh_interval_ms.
Source: https://developers.openai.com/codex/config-reference, https://developers.openai.com/codex/config-advanced
Header injection is hardcoded to Authorization: Bearer <token>. No configurable header name exists. No api-key code path is taken when auth.command is set.
Source: codex-rs/model-provider/src/bearer_auth_provider.rs in https://github.com/openai/codex
auth is mutually exclusive with env_key, experimental_bearer_token, requires_openai_auth. Do not combine them.
No built-in azure provider. Built-ins are only openai, amazon_bedrock (special SigV4 branch), ollama, lmstudio. The [model_providers.azure] string in community configs is just a user-chosen label — no special casing.
Source: codex-rs/model-provider-info/src/lib.rs
No base_url hostname validation. Issue #4278's historical Azure-hostname rejection is not present in the current main branch. Any HTTPS URL is accepted.
Source: codex-rs/config/src/host_name.rs, codex-rs/config/src/cloud_requirements.rs
Outbound headers Codex sends on Responses API calls. Beyond Authorization and Accept: text/event-stream (for streaming), Codex attaches a family of x-codex-* headers: x-codex-installation-id, x-codex-turn-state, x-codex-turn-metadata, x-codex-parent-thread-id, x-codex-window-id, plus x-client-request-id. Optionally x-openai-subagent, x-openai-memgen-request, and OpenAI-Beta: responses_websockets=... on WebSocket paths. These are non-standard; Azure is expected to ignore them (standard HTTP behavior), but this has not been empirically confirmed against a live Azure endpoint.
Source: codex-rs/core/src/client.rs, codex-rs/codex-api/src/endpoint/responses.rs, codex-rs/codex-api/src/sse/responses.rs
Upstream issue history:
- #4278 (closed) — Azure bearer + custom DNS support: openai/codex#4278
- #9083 (closed as not planned) — native Entra client-credentials: openai/codex#9083
- #15189 (closed via PR #16288) — dynamic bearer token refresh; this PR added
auth.command: openai/codex#15189 - #8732 (open) — DefaultAzureCredential request; implicitly confirms
auth.command+azas today's sanctioned workaround: openai/codex#8732
Required role: Cognitive Services OpenAI User on the OpenAI / Foundry resource. The Cognitive Services Contributor role does NOT grant data-plane inference.
Source: https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/role-based-access-control
disableLocalAuth: true on the resource is what disables api-key auth; Entra bearer calls still work. The toggle takes a few minutes to propagate. Custom subdomain is required for Entra auth on Cognitive Services resources, and is provisioned by default for Foundry-created resources.
Source: https://learn.microsoft.com/en-us/azure/ai-services/disable-local-auth ; https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/managed-identity
v1 API path. POST https://<res>.openai.azure.com/openai/v1/responses is the current GA Responses endpoint; no ?api-version= query needed. It accepts Authorization: Bearer <entra-token>.
Source: https://learn.microsoft.com/en-us/azure/foundry/openai/api-version-lifecycle ; https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/responses ; https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/codex
Token scope. For az account get-access-token, use --resource https://cognitiveservices.azure.com (MSAL appends .default internally). Newer Foundry Python samples use scope https://ai.azure.com/.default; both are accepted by the data-plane. Prefer cognitiveservices.azure.com as the stable, longest-lived form.
Source: Azure.AI.OpenAI .NET README; Foundry managed-identity Python sample.
Microsoft's Codex + Azure guide explicitly states "Entra ID support is currently not available for Codex" and only documents api-key auth. This refers to native first-class integration; it does not address OpenAI's auth.command workaround (which is a Codex-side feature Microsoft has not documented). Not a technical blocker.
Source: https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/codex (2026-04-14)
Model availability. gpt-5-codex, gpt-5.1-codex{,-mini,-max}, gpt-5.2-codex, gpt-5.3-codex are GA in Global Standard across many regions with no allowlist gating.
Deployment vs model name. On Azure, the model field of the Responses API request body routes by the deployment name (what you chose in Foundry), not the catalog model name. A mismatch returns 404.
The Phase 0 config in PLAN.md works iff:
- Codex CLI version includes PR #16288 (the
auth.commandmechanism). az loginis completed and the principal hasCognitive Services OpenAI Useron the target resource.- The
modelfield in the config is the Azure deployment name. - Azure silently ignores
x-codex-*headers (empirical; expected per standard HTTP).
(1), (2), (3) are user-controlled and verifiable with the commands in §5 of PLAN.md. (4) is the sole empirical uncertainty and is mitigated by a thin header-sanitizer proxy (~100 lines) if it fails.
After az login and role assignment, the fastest end-to-end validation that does not involve Codex at all:
TOKEN=$(az account get-access-token --resource https://cognitiveservices.azure.com --query accessToken -o tsv)
curl -sS -X POST "https://<RESOURCE>.openai.azure.com/openai/v1/responses" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"model":"<DEPLOYMENT_NAME>","input":"ping"}' | jq .A 200 with a Responses payload here means every Azure-side assumption is valid; only Codex-side details remain to verify.