Add Jurisdictional Token Flag to Auth Command · Entire
We have entire auth token add a flag to output a jurisdictional token so that I can use it on e.g. https://aws-us-east-2.api.entire.io/api/v1. I should be able to specify the jurisdiction.
Plan: add --jurisdiction to entire auth token
The key finding: the entire jurisdictional-token exchange pipeline already exists in cmd/entire/cli/auth/cell_data_api.go (exchangeJurisdictionToken, jurisdictionAudience, jurisdictionCoreURL, targetJurisdiction). It's consumed by NewEntireAPICellClient, which returns a wrapped *api.Client instead of the raw token. So this is mostly exposing existing, already-audited logic rather than writing new exchange/security code.
The change, in three parts:
- Expose the token — a new
auth.JurisdictionToken(ctx, insecureHTTP, jurisdiction)that runs the same discover → resolve-subject → RFC 8693 exchange flow but returns the token string (skipping the cell-URL resolution only a client needs). Honoring your two decisions: flag value is a slug (us,eu), andENTIRE_TOKENis used as the exchangesubject_tokenwhen set. Minor refactors keepNewEntireAPICellClient's behavior identical. - Wire the flag —
--jurisdictiononnewAuthTokenCmd; when non-empty it mints & prints the jurisdictional token (stdout stays clean for$(...)), otherwise the current control-plane behavior is untouched. - Docs —
CLAUDE.mdauth bullet +CHANGELOG.md.
Result:curl -H "Authorization: Bearer $(entire auth token --jurisdiction us)" https://aws-us-east-2.api.entire.io/api/v1/... works.
Tests reuse the existing SetResolveContextForCellAPIForTest / SetCellExchangeTransportForTest httptest seams, covering both the stored-login and ENTIRE_TOKEN subject paths, plus a command-level test.
Base directory for this skill: /Users/georgf/.claude/skills/grill-me
Question 1 — Input contract & discoverability.
The token's aud is the jurisdiction host (https://us.entire.io), not the cell host. So the flag value is a jurisdiction slug like us, and that one token works against any cell in that jurisdiction (including your example aws-us-east-2.api.entire.io). But a user staring at aws-us-east-2.api.entire.io/api/v1 has no CLI-supported way to learn that its slug is us — auth status doesn't print it, and the only slug UI is the interactive mirror wizard.
So: how should a user discover the value, and should the flag accept anything beyond a bare slug?
My recommendation: Keep --jurisdiction accepting only a lowercase slug (crisp contract, matches the internal jurisdictionLabelPattern and the existing --region values). To close the discovery gap, also print the home jurisdiction in entire auth status (one line, e.g. Region: us) as part of this change.
Question 2 — ENTIRE_TOKEN exchange: environment detection & the "must be a login JWT" limitation.
You chose to honor ENTIRE_TOKEN as the exchange subject_token. Tracing the exchange path surfaces two things worth nailing down:
- Environment auto-detection. The shared helpers pick prod-vs-staging from
environmentFamily(dataOrigin, discoveredCore), anddataOrigindefaults tohttps://entire.io( prod) unlessENTIRE_API_BASE_URLis set. A CI job that only exportsENTIRE_TOKEN(the common case) — especially a staging token — would otherwise get mis-templated to prod cores. The env token's ownaud(viaParseEnvToken) unambiguously encodes its environment. - Exchange happens at the target jurisdiction's core (
https://{j}.auth.<family>/oauth/token), not the token's home core — this is the existing cross-jurisdiction identity flow. It only works ifENTIRE_TOKENis a login JWT (subject-capable); an already-exchanged cell/foreign token gets rejected (the server refuses chained exchanges).
My recommendation:
- In the ENTIRE_TOKEN path, derive the environment family (and loopback detection) from the env token's own
audcore, soentire auth token --jurisdiction euworks with onlyENTIRE_TOKENset — noENTIRE_API_BASE_URLneeded — in prod, staging, or local dev. - Keep the exchange target as
jurisdictionCoreURL(...)(same audited templating as the stored path), so cross-jurisdiction minting behaves identically regardless of subject source. - Document the limitation:
ENTIRE_TOKENmust be a login JWT; on a rejected exchange, surface the server error verbatim rather than masking it.
Question 3 — Slug normalization.
resolveJurisdiction validates the value against jurisdictionLabelPattern, which is lowercase-only ([a-z0-9-]). The existing --region flag on org/project passes its value verbatim to the server (no client normalization). But our path validates client-side, so entire auth token --jurisdiction US would fail with "US" is not a valid label — a jarring error for something that unambiguously means us.
My recommendation: normalize the explicit slug (strings.TrimSpace + strings.ToLower) inside resolveJurisdiction's override branch before the pattern check, so --jurisdiction US / " us " / us all work. Slugs are lowercase DNS labels — there's no valid uppercase variant that means something else — so lowercasing can't mask a real distinction, and the pattern still guards against injection. (The home-fallback branch reads an already-lowercase claim, so it's unaffected.)
Question 4 — Should the flag have a "home jurisdiction" shortcut, or always require a slug?
JurisdictionToken already falls back to the subject token's home_jurisdiction claim when the slug is empty. That opens a design choice for the command surface:
- (A) Slug always required when using the flag:
--jurisdiction eu. Bareentire auth tokenstays the control-plane path. Simple; detection is just "flag value non-empty". - (B) Optional-value flag:
entire auth token --jurisdiction(no value) mints for your home jurisdiction — the common "just give me a cell token" case — and--jurisdiction eutargets a specific one. Requires cobraNoOptDefVal+cmd.Flags().Changed(...)detection.
My recommendation: (A), slug always required. It matches your original ask ("specify the jurisdiction"), keeps the flag's contract unambiguous (a string flag that sometimes takes no value is a papercut), and the home case is no longer opaque now that auth status prints the slug. The home-fallback stays in the library function for internal reuse but isn't surfaced on the flag.
Question 5 — Any stderr diagnostics on success, or token-only?
The minted token goes to stdout. The token's aud (jurisdiction host, e.g. https://us.entire.io) differs from the cell URL the user curls (https://aws-us-east-2.api.entire.io/api/v1). We could echo the resolved audience/exchange-core to stderr as a debugging aid.
My recommendation: token-only, no success chatter. It matches today's auth token contract (only the token on stdout, only errors on stderr, so $(entire auth token --jurisdiction us) stays clean), and the user already knows the cell URL they're targeting. Diagnostics on failure still surface via the wrapped exchange error. If deeper tracing is ever needed, the existing --insecure-http-auth/debug-logging paths cover it.
Done. Here's what shipped.
entire auth token --jurisdiction <slug>
Feature — entire auth token --jurisdiction us now mints and prints a jurisdictional identity token (RFC 8693 exchange, scope=openid, aud=<jurisdiction host>) for use against that jurisdiction's entire-api cells like https://aws-us-east-2.api.entire.io/api/v1, which reject the control-plane bearer. Bare entire auth token is unchanged.
Implementation (per the grilled plan):
cmd/entire/cli/auth/cell_data_api.go— new exportedJurisdictionToken, built by extracting a shared subject-resolution helper (cellSubject/resolveStoredCellSubject/resolveEnvTokenCellSubject/cellExchangeHTTPClient) out ofNewEntireAPICellClient(whose behavior is unchanged — it still ignoresENTIRE_TOKEN).targetJurisdictionsplit intoresolveJurisdiction, which trims + lowercases the slug.ENTIRE_TOKENis honored as the exchange subject (exclusive, fail-closed), with the environment (prod/staging/loopback) derived from the token's ownaud— so it works in CI with noENTIRE_API_BASE_URL.cmd/entire/cli/auth.go— the--jurisdictionflag/branch (slug required, token-only stdout, clean not-logged-in hint) plus a newJurisdiction:line inauth statusso the slug is discoverable (labels widened to align).- Docs:
CLAUDE.md(=AGENTS.md) auth bullet and aCHANGELOG.mdUnreleased entry.
Tests — JurisdictionToken stored-context + ENTIRE_TOKEN paths (asserting subject_token, scope=openid, audience), the --jurisdiction command path (env-token success + not-logged-in), and the auth status slug line.