Service-plane tokens
Client-credentials tokens from the cross-service auth server, and the three scopes that partition /internal.
Everything under /internal/v1/* authenticates with an OAuth 2.0 client-credentials token from the cross-service auth server (cross-auth): your service authenticates with its private key (private_key_jwt), names this service as the resource, and receives a short-lived RS256 JWT whose scope decides what it may do here. User tokens never work on this plane.
Getting a token
import httpx
token = httpx.post(CROSS_AUTH_TOKEN_URL, data={
"grant_type": "client_credentials",
"client_id": "translation-service",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": signed_client_jwt, # signed with your registered key
"resource": "https://provider-credentials.internal",
}).json()["access_token"]
The resource is this service's logical identifier in the auth registry (not a network URL); requests then go to the service's public domain as usual. Which clients may hold which scopes is the auth registry's access matrix — onboarding a new consumer is a registry change there, not a change here.
The three scopes
| Scope | Unlocks | Typical holder |
|---|---|---|
provider-credentials.invoke |
resolve | translation runtimes |
provider-credentials.admin |
credential administration | the admin panel's backend |
provider-credentials.reveal |
plaintext reveal | the admin panel's backend, granted separately |
None implies another — the separation is two-directional on purpose: an admin token cannot read plaintext (neither via resolve nor reveal), and an invoke token cannot administer. A valid token with the wrong scope is a 403; a missing/invalid token is a 401.
Conventions on this plane
X-Admin-Actor— admin and reveal calls attribute the human operator behind the service (Internal Admin API); mandatory on reveal.correlation_id— resolve takes it in the body and threads it through the audit trail.- Fail-closed — a deployment without service-auth configuration answers
401on the whole plane rather than trusting anyone.
The registration itself (client key, resource URI, scope grants) lives in the auth server's own repository and docs; from this service's perspective a consumer either arrives with the right scope or it does not.