Files
esh-pfi-infrastructure/services/grok-token-broker

grok-token-broker

Holds a refreshable xAI session credential so a gateway can serve the Grok Build coding plan — without touching the credential the operator's grok CLI depends on.

seed            copy the CLI credential into the broker's own store (read-once)
probe-rotation  MEASURE whether refresh rotates AND invalidates  <- gate
token --raw     emit a valid access token, refreshing if near expiry
refresh         refresh now
status          report state, touching nothing

The problem

The coding plan (https://cli-chat-proxy.grok.com/v1, serving grok-4.6, 500k context) authenticates with an OIDC session token — api_key: null, env_key: null in the CLI's own model cache — that expires roughly every six hours. LiteLLM and every other gateway here hold a static credential, so a naive alias works until the session lapses and then fails closed.

⛔ Why the loop is disarmed until measured

https://auth.x.ai/oauth2/token supports the refresh grant. But a refresh may rotate the refresh token, and many providers invalidate the old one server-side the moment a new one issues. The grok CLI holds its refresh token in ~/.grok/auth.json.

Not writing to that file is necessary and not sufficient. If xAI rotates-and-invalidates, a broker refreshing the same credential kills the CLI login anyway, server-side. heid's groa_http_dispatch.py refuses to refresh at all for exactly this reason — correct, absent an answer. This broker exists to get the answer, then act on it.

So probe-rotation is a gate, not a diagnostic: refresh and token-near-expiry both refuse until a verdict exists and says safe.

verdict meaning
non-rotating same refresh token returned. Coexistence safe. Armed.
rotating-old-still-valid rotation happens, old token still works. Coexistence safe. Armed.
rotating-and-invalidating the CLI login is already dead. Broker must not share this credential — it needs its own login. Stays disarmed.

⚠ The probe spends one refresh, and there is no way to ask the question without spending it. If the answer is the bad one, the CLI is broken at that moment and needs an interactive grok re-login — the same remedy heid's exit-3 path already names. Run it when a broken CLI login is a two-minute annoyance, not mid-panel. Hence the required --i-accept-this-may-end-the-cli-session flag.

Current state

Seeded on nh3-dev 2026-09-16. Scope openid profile email offline_access grok-cli:access api:access, client b1a00492-…. Probe NOT yet run — it is the operator's call when to spend it.

For a consumer

TOKEN=$(broker.py token --raw)
curl https://cli-chat-proxy.grok.com/v1/... -H "Authorization: Bearer $TOKEN"

⚠ The coding plan speaks the Responses API (api_backend: "responses"), not /chat/completions. That is a second, independent obstacle to a LiteLLM alias and this broker does not solve it — it solves the credential half only.

Invariants

  • Never writes ~/.grok/auth.json. Reads it once, on seed.
  • Never prints a token except under token --raw.
  • Never logs a token value — expiry, scope and subject only.
  • Store is ~/.config/grok-token-broker/ at 0700, credential at 0600.