solo enterprise agentgateway · entra jwt · xai openai dialect

Grok Build Gateway · Entra JWT → xAI

Dedicated gateway for Grok Build (xAI CLI / BYOK custom models). Strict JWT on the data plane against Microsoft Entra ID, then xAI via the Vault-synced API key. Grok Build talks the Responses API (or chat completions) 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 + xai-secret
Lab page Markdown deep-dive Proxy script Grok Build repo xAI Build docs k8s-goose repo All links ↓

#Architecture

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

1 · Entra
Public client
agw-grok-build
2 · Bearer
ID token
not access token
3 · Gateway
JWT Strict
entra-jwks
4 · Upstream
xAI
xai-secret

Path is / on this dedicated Gateway so Grok Build can call {base}/v1/responses. The kagent xAI path stays on xai-grok-gateway at :31397/grok (grok-4.5 pinned — do not steal it). Sibling Codex path: codex.html.

#Live endpoint

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

Primary lab path — LAN HTTP

Grok Build base URL: http://172.16.10.155:31918/v1 (the /v1 suffix is required). Optional loopback: python3 scripts/grok-build-lab-proxy.py (default GROK_BUILD_GW_NODEPORT=31918) → http://127.0.0.1:18791/v1.

ThingValue
Servicegrok-build-gateway · ns agentgateway-system
Grok Build base URL (LAN)http://172.16.10.155:31918/v1
Grok Build base URL (loopback, optional)http://127.0.0.1:18791/v1 · via scripts/grok-build-lab-proxy.py
Responses path{base}/responses…/v1/responses
Models path{base}/models…/v1/models · set GROK_MODELS_BASE_URL to the same base_url
HTTP NodePort172.16.10.155:31918 · Service 80:31918/TCP
HTTPS NodePort (optional / advanced)https://172.16.10.155:31987/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 grok-build-gateway (HTTP from port 80, HTTPS from port 443). Anonymous calls must 401/403; a valid Entra ID token reaches xAI.

#Entra app

Public client already registered — do not recreate.

FieldValue
App nameagw-grok-build
Tenant ID8635e970-2205-4189-bc77-77519ff5064f
Client ID36fb017c-5b4b-4c26-9bd7-7af25793178b
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)

#Grok Build config

base_url must end in /v1. GROK_AGW_TOKEN must be an Entra ID token for agw-grok-build (gateway JWT aud = client ID). Grok Build sends it as Authorization: Bearer. Access tokens fail.

~/.grok/config.toml

config.toml · BYOK model via agentgateway (lab)
[model.agw]
model = "grok-4.5"
base_url = "http://172.16.10.155:31918/v1"
name = "Grok via agentgateway"
env_key = "GROK_AGW_TOKEN"
api_backend = "responses"
supports_backend_search = false

[models]
default = "agw"

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

supports_backend_search must be false on this BYOK gateway — xAI server-side search tools will not exist through AgentGateway. Optional: export GROK_MODELS_BASE_URL="http://172.16.10.155:31918/v1" so the client lists models from {base}/models (this gateway maps /v1/modelsModels).

api_backend may be responses (recommended), chat_completions (/v1/chat/completions), or messages (Passthrough). Prefer responses — same wire as Codex.

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=36fb017c-5b4b-4c26-9bd7-7af25793178b

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}"
/v1/models

Models route exists

Backend maps /v1/modelsModels. Set GROK_MODELS_BASE_URL to the same base_url if Grok Build lists models from {base}/models.

does not steal /grok

kagent path intact

Dedicated Gateway + PathPrefix /. The grok-4.5 /grok route on xai-grok-gateway (:31397) is unchanged.

#Critical callouts

Bearer must be an ID token

Gateway aud = agw-grok-build client ID. Access tokens (az account get-access-token) have a different audience story and will fail Strict JWT. Grok Build env_key = GROK_AGW_TOKEN.

base_url must end in /v1

Grok Build posts {base}/v1/responses. A URL without the suffix 404s. Do not point Grok Build at :31397/grok.

supports_backend_search = false

xAI server-side search tools will not exist through this BYOK AgentGateway path. Leave supports_backend_search = false on [model.agw].

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
Gatewaygrok-build-gatewayconfig/gateway/grok-build-gateway.yaml
HTTPRoutegrok-buildconfig/routes/grok-build-route.yaml
AgentgatewayBackendxai-grok-buildconfig/backends/xai-grok-build.yaml
AgentgatewayPolicygrok-build-jwt-authconfig/policies/grok-build-jwt-auth.yaml
tracing targetRefGateway grok-build-gatewayconfig/policies/tracing.yaml
Lab proxy scriptscripts/grok-build-lab-proxy.py
Markdown deep-divedocs/grok-build-gateway.md
Reused — do not recreate

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

#AgentGateway config

Live GitOps YAML for this dedicated gateway (Argo app agentgateway-config). Copy a resource below, or open the GitHub blob. There is no first-party Grok Build client page — start at the LLM clients index, then the xAI provider and Solo openai-compatible (xAI) host/path table. xAI speaks the OpenAI dialect. Does not steal /grok on xai-grok-gateway (:31397).

Gateway · grok-build-gateway · GitHub
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: grok-build-gateway
  namespace: agentgateway-system
spec:
  gatewayClassName: enterprise-agentgateway
  # Load the shared model cost catalog so this gateway's LLM traffic is priced
  # in USD for Cost Management. Without this, spans on this gateway compute
  # CostUsd=0 regardless of catalog contents (only gateways with a parametersRef
  # price requests). Same params object as agentgateway-proxy / codex.
  infrastructure:
    parametersRef:
      group: enterpriseagentgateway.solo.io
      kind: EnterpriseAgentgatewayParameters
      name: agentgateway-proxy-params
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: All
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - name: solo-ui-tls
            kind: Secret
      allowedRoutes:
        namespaces:
          from: All
HTTPRoute · grok-build · GitHub
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: grok-build
  namespace: agentgateway-system
spec:
  parentRefs:
    - name: grok-build-gateway
      namespace: agentgateway-system
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: xai-grok-build
          namespace: agentgateway-system
          group: agentgateway.dev
          kind: AgentgatewayBackend
AgentgatewayBackend · xai-grok-build · GitHub
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayBackend
metadata:
  name: xai-grok-build
  namespace: agentgateway-system
  labels:
    app.kubernetes.io/component: grok-build
    app.kubernetes.io/part-of: entra-id
spec:
  ai:
    provider:
      openai: {}
      host: api.x.ai
      port: 443
      pathPrefix: /v1
  policies:
    ai:
      routes:
        "/v1/responses": Responses
        "/v1/chat/completions": Completions
        "/v1/models": Models
        "*": Passthrough
    auth:
      secretRef:
        name: xai-secret
    tls:
      sni: api.x.ai
AgentgatewayPolicy · grok-build-jwt-auth · GitHub
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayPolicy
metadata:
  name: grok-build-jwt-auth
  namespace: agentgateway-system
  labels:
    app.kubernetes.io/component: grok-build
    app.kubernetes.io/part-of: entra-id
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      name: grok-build
  traffic:
    jwtAuthentication:
      mode: Strict
      providers:
        - issuer: https://login.microsoftonline.com/8635e970-2205-4189-bc77-77519ff5064f/v2.0
          audiences:
            - "36fb017c-5b4b-4c26-9bd7-7af25793178b"
          jwks:
            remote:
              backendRef:
                name: entra-jwks
                kind: AgentgatewayBackend
                group: agentgateway.dev
                port: 443
              jwksPath: /8635e970-2205-4189-bc77-77519ff5064f/discovery/v2.0/keys
              cacheDuration: 5m