solo enterprise agentgateway · entra jwt · openai responses api

Codex Gateway · Entra JWT → OpenAI

Dedicated gateway for OpenAI Codex (CLI + ChatGPT desktop Codex). Strict JWT on the data plane against Microsoft Entra ID, then OpenAI via the Vault-synced API key. Codex talks the Responses API and allows plain HTTP off loopback — LAN NodePort is the primary lab path; the loopback proxy is optional.

base_url must end in /v1 ID token · Strict JWT /v1/responses reuses entra-jwks + openai-secret
Lab page Markdown deep-dive Proxy script Solo Codex docs k8s-goose repo All links ↓

#Architecture

Codex authenticates with an Entra ID token as Bearer (CODEX_AGW_TOKEN), the gateway validates it Strict against Entra JWKS, then injects the OpenAI key upstream. Model is not pinned — Codex sends it per request.

1 · Entra
Public client
agw-codex
2 · Bearer
ID token
not access token
3 · Gateway
JWT Strict
entra-jwks
4 · Upstream
OpenAI
openai-secret

Path is / on this dedicated Gateway so Codex can call {base}/v1/responses. The kagent OpenAI path stays on agentgateway-proxy at :30160/openai (gpt-5.5 pinned — do not steal it). Sibling Claude Desktop path: claude-desktop.html.

#Live endpoint

Bare-metal NodePort on worker 172.16.10.155. Codex allows plain HTTP off loopback, so the LAN URL is valid. Live Service ports: HTTP 80:31928/TCP, HTTPS 443:31540/TCP.

Primary lab path — LAN HTTP

Codex base URL: http://172.16.10.155:31928/v1 (the /v1 suffix is required). Optional loopback: python3 scripts/codex-lab-proxy.py (default CODEX_GW_NODEPORT=31928) → http://127.0.0.1:18790/v1.

ThingValue
Servicecodex-gateway · ns agentgateway-system
Codex base URL (LAN)http://172.16.10.155:31928/v1
Codex base URL (loopback, optional)http://127.0.0.1:18790/v1 · via scripts/codex-lab-proxy.py
Responses path{base}/responses…/v1/responses
HTTP NodePort172.16.10.155:31928 · Service 80:31928/TCP
HTTPS NodePort (optional / advanced)https://172.16.10.155:31540/v1 · TLS Terminate · Secret solo-ui-tls
Confirm NodePorts

If ports ever change, re-confirm with kubectl --context maniak-goose -n agentgateway-system get svc codex-gateway (HTTP from port 80, HTTPS from port 443). Anonymous calls must 401/403; a valid Entra ID token reaches OpenAI. Codex CLI tested at 0.144.4.

#Entra app

Public client already registered — do not recreate.

FieldValue
App nameagw-codex
Tenant ID8635e970-2205-4189-bc77-77519ff5064f
Client IDe862e87d-d284-46a8-bf70-30ac7dba351e
Issuerhttps://login.microsoftonline.com/8635e970-2205-4189-bc77-77519ff5064f/v2.0
PlatformMobile and desktop applications
Redirect URIhttp://127.0.0.1/callback
Public client flowsYes (no client secret · isFallbackPublicClient: true)

#Codex CLI + ChatGPT desktop config

base_url must end in /v1. CODEX_AGW_TOKEN must be an Entra ID token for agw-codex (gateway JWT aud = client ID). Codex sends it as Authorization: Bearer. Access tokens fail.

~/.codex/config.toml

config.toml · agentgateway provider (lab)
model_provider = "agentgateway"

[model_providers.agentgateway]
name = "OpenAI via agentgateway"
base_url = "http://172.16.10.155:31928/v1"
wire_api = "responses"
env_key = "CODEX_AGW_TOKEN"

Loopback variant: base_url = "http://127.0.0.1:18790/v1".

CLI one-shot

From Solo Codex docs plus env_key:

codex CLI · one-shot
export AGENTGATEWAY_BASE_URL="http://172.16.10.155:31928/v1"
export CODEX_AGW_TOKEN='<entra id_token>'

codex -c 'model_provider="agentgateway"' \
  -c 'model_providers.agentgateway.name="OpenAI via agentgateway"' \
  -c "model_providers.agentgateway.base_url=\"${AGENTGATEWAY_BASE_URL}\"" \
  -c 'model_providers.agentgateway.wire_api="responses"' \
  -c 'model_providers.agentgateway.env_key="CODEX_AGW_TOKEN"' \
  "Hello"

Mint an ID token

Device-code against the public client (no secret). Copy id_token, not access_token.

Entra device code · id_token
TENANT=8635e970-2205-4189-bc77-77519ff5064f
CLIENT=e862e87d-d284-46a8-bf70-30ac7dba351e

curl -sS -X POST "https://login.microsoftonline.com/${TENANT}/oauth2/v2.0/devicecode" \
  -d "client_id=${CLIENT}" \
  -d "scope=openid profile email offline_access"

# complete user_code in a browser, then:
curl -sS -X POST "https://login.microsoftonline.com/${TENANT}/oauth2/v2.0/token" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
  -d "client_id=${CLIENT}" \
  -d "device_code=${DEVICE_CODE}"

ChatGPT desktop Codex

Same provider block. Back up and replace the user-level config, then restart the app — or Settings → Configuration → Open config.toml. Export CODEX_AGW_TOKEN in the environment that launches the app.

ChatGPT desktop · ~/.codex/config.toml
{
  "model_provider": "agentgateway",
  "model_providers": {
    "agentgateway": {
      "name": "OpenAI via agentgateway",
      "base_url": "http://172.16.10.155:31928/v1",
      "wire_api": "responses",
      "env_key": "CODEX_AGW_TOKEN"
    }
  }
}

JSON-ish equivalent of the TOML (the app file is still TOML). Profile form: codex --profile agentgateway with ~/.codex/agentgateway.config.toml.

/v1/models probe

Warning is OK

Codex probes /v1/models. Until agentgateway#1462 adds a gateway-generated list, Codex may warn that model metadata is not found. That does not block /v1/responses.

does not steal /openai

kagent path intact

Dedicated Gateway + PathPrefix /. The gpt-5.5 /openai route on agentgateway-proxy is unchanged.

#Critical callouts

Bearer must be an ID token

Gateway aud = agw-codex client ID. Access tokens (az account get-access-token) have a different audience story and will fail Strict JWT. Codex env_key = CODEX_AGW_TOKEN.

base_url must end in /v1

Codex posts {base}/v1/responses. A URL without the suffix 404s. Do not point Codex at :30160/openai.

Redirect must include /callback

Register http://127.0.0.1/callback under Mobile and desktop applications. Public client, no secret. Do not recreate the Entra app.

#Cluster resources

GitOps under config/ via Argo app agentgateway-config. Push + sync is enough. File paths link to GitHub main.

KindNameFile
Gatewaycodex-gatewayconfig/gateway/codex-gateway.yaml
HTTPRoutecodexconfig/routes/codex-route.yaml
AgentgatewayBackendopenai-codexconfig/backends/openai-codex.yaml
AgentgatewayPolicycodex-jwt-authconfig/policies/codex-jwt-auth.yaml
tracing targetRefGateway codex-gatewayconfig/policies/tracing.yaml
Lab proxy scriptscripts/codex-lab-proxy.py
Markdown deep-divedocs/codex-gateway.md
Reused — do not recreate

AgentgatewayBackend/entra-jwks · Secret/openai-secret (+ ExternalSecret → Vault) · Secret/solo-ui-tls (HTTPS terminate; same ns as Gateway) · EnterpriseAgentgatewayParameters/agentgateway-proxy-params (cost catalog) · Entra app agw-codex