Skip to main content

Authenticate gateway requests with an external IdP

Enterprise Tier

A request to a data plane authenticates with an API key issued for the project, or carries the caller's own provider credential on the passthrough path. From 0.7.0 an application can instead present a token minted by the organization's own identity provider, verified at the gateway against a set of registered issuers. That token path is a preview: it works end to end, budgets and rate limits do not yet apply to it, and a worked example for one provider is forthcoming.


Preview: authenticating with an identity-provider token

The token path shipped in two steps. 0.6.0 stores gateway auth policies and verifies a token sent beside an API key. 0.7.0 serves a call made with a token alone, provided every data plane serving the project is on 0.7.0 or later. Budgets and rate limits are recorded per API key and do not yet apply to a caller admitted by a token, so cap that usage at the identity provider until they do. A worked configuration for one real provider, with a real token shape, is forthcoming and is published when the customer-side claim decisions it depends on are settled. Until then, the management API reference linked below is the complete field list.

What authenticates a request at 0.7.0​

A request reaches a project through a hostname the data plane declares, and every project the data plane carries a project label for is served on every one of its hostnames. Nothing about the hostname selects the project: the credential does. Three credentials exist.

  • An API key issued for the project, on the Authorization header. The key names its project, so the request needs no other identifier, and a key from a project the data plane does not serve is refused with 403. Keys are issued by developers in the Console and governed organization-wide by operators; issuing, auditing, and revoking them is covered in Onboard developers and issue keys and Issue a project API key.
  • The caller's own provider credential, on the passthrough path: the request carries a credential for the upstream provider itself (an Anthropic subscription token, for example), and the gateway forwards rather than substitutes it. The behavior and its routing consequences are covered in Use your own provider credentials and, for the operator-side setup, Enable passthrough for Claude Code.
  • A token from the organization's own identity provider, in preview from 0.7.0, sent in the standard Authorization: Bearer header together with a header naming the project. The rest of this page describes it.

Single sign-on is a different surface: SSO authenticates people into the consoles, and its identities can then issue API keys. It never authenticates a request to a data plane.

How a token call works​

An API key names exactly one project. A token names an application, and an application may be entitled to several projects, so a token call carries one extra header naming the project the request runs as. The data plane takes that header as a candidate, never as a decision: the configuration the project publishes decides whether this token may use it.

Two configurations admit a token, and they are shaped for different situations.

ConfigurationWhere it is writtenWho it suits
A gateway auth policy, with identity mapping rules, on a gatewayThe GatewayAuthPolicyService of the management API, one policy per trusted issuer, up to four enabled per gatewayAn operator registering a set of issuers once for every project served on that gateway, with per-issuer key sources, audiences, and required scopes
A project OIDC contract, on one projectUpsertProjectOIDCConfig, one contract per projectA project team naming the one issuer, audience, scope, and optional entitlement its own tokens carry

On either path the data plane verifies the token's signature against the issuer's key set, its expiry, and its audience, then checks what the configuration requires of its claims, and only then resolves the project. A token from an issuer the gateway does not register is refused rather than tried against another issuer's keys.

The set of trusted issuers​

One gateway carries several trusted identity providers, each with its own key source and its own accepted audiences. Every policy names its issuer, and one gateway takes at most one enabled policy per issuer, so the gateway selects the verifier from the issuer the token names and nothing else. The policy fields:

FieldWhat it does
issuerThe value the token's iss claim must carry. Required, and unique among the gateway's enabled policies.
jwks_uri or jwks_inlineWhere the signing keys come from. A jwks_uri must name the provider by a public hostname, carry no user name or password, and not resolve to an internal address. An inline key set holds at most 32 keys and 16 KiB; serve a larger set from a jwks_uri.
audiencesThe audiences a token may carry, up to eight.
required_scopesScopes the token must carry, every one of them, in its scope or scp claim, matched case-sensitively. A token missing one gets 403. Updates replace the list, so omitting it removes the requirement.
extraction_headerThe header the token is read from when it is not sent as a Bearer value. Defaults to x-tars-idp-token. Authorization is refused, as is any header the gateway cannot remove after verification, such as x-api-key or cookie.
environment_claimThe claim carrying the environment the token was issued for, compared against the environment the gateway declares. An enabled policy naming one is refused while the gateway declares no environment, and the gateway refuses a token whose claim does not name its environment.

Identity mapping rules, under the same service, say which claim identifies the application and whether an application unseen before is given an identity on its first call (jit, bounded by a per-project cap) or must be pre-registered. A jit rule names the project the application is created in, and that project has to be attached to the policy's gateway before the rule is written.

Which credentials a project accepts​

Each project's membership of a gateway records accepted_credentials, written with UpdateProjectGatewayProject. A new attachment starts at ACCEPTED_CREDENTIALS_API_KEY, which is what every project did before the field existed. ACCEPTED_CREDENTIALS_BOTH admits either credential, and ACCEPTED_CREDENTIALS_TOKEN makes the data plane refuse API keys for that project. Both are refused while the project holds no enabled policy on that gateway, and the project's last enabled policy cannot be disabled or deleted while the membership declares either one. A data plane older than 0.7.0 authenticates API keys alone, whatever the membership declares.

What an application sends​

The same base URL, endpoints, and model names as an API-key caller, plus the project header:

curl https://gw.example.com/v1/chat/completions \
-H "Authorization: Bearer $IDP_TOKEN" \
-H "x-tars-project: payments-assist" \
-d '{"model": "claude-sonnet-4-5", "messages": [{"role": "user", "content": "Hello"}]}'

The header is x-tars-project on the gateway auth policy path and X-TARS-PROJECT-ID on the project OIDC contract path; both take the project's name. The data plane removes either header, and the token, before anything is forwarded to a model provider or an MCP server. A request that carries both a token and an x-api-key header is refused as a credentials conflict rather than guessed at.

On the gateway auth policy path, the first call from an application creates the application's own API key when a mapping rule allows it, and later calls reuse it. Request logs and usage are attributed to that key, which is how a token call appears in the Console today.

What a refusal means​

Each refusal carries its own reason in the error body, and the data plane records the reason in its metrics. The ones a caller is most likely to meet:

StatusReasonMeaning
400missing_project or project_header_requiredThe request carries a token and no project header.
400credentials_conflictThe request carries both a Bearer token and an x-api-key header.
401unregistered_issuerThe token's iss names an issuer this gateway does not register.
401bad_signature, expired, wrong_audienceThe token did not verify against the issuer's keys, has expired, or was not issued for an audience the gateway accepts.
403project_not_servedThe gateway does not serve the project the header names.
403token_not_acceptedThe project named accepts API keys only on this gateway.
403issuer_not_acceptedThe issuer is registered on the gateway, but the project named does not accept tokens from it.
403missing_scope or insufficient_scopeThe token lacks a scope the policy or contract requires.
403environment_mismatchThe token's environment claim does not name the gateway's environment.
503keys_unavailableThe gateway does not hold the issuer's keys right now. Retry.

A 403 on the project contract path that names nothing is deliberate: a project a token has no relationship with confirms neither that the project exists nor whose token this is. Every refusal carries a reference_id to quote to support.

What is refused when a policy is written​

The management API refuses a gateway auth policy write, with the reason in the response, when:

  • jwks_uri carries a user name or password, writes an IPv4 address as anything other than a dotted quad, or names or resolves to a carrier-grade NAT, multicast, reserved, or other internal address;
  • jwks_inline holds more than 32 keys or more than 16 KiB;
  • extraction_header is one the gateway cannot remove after verifying the token, which rules out the identity headers the gateway sets and credential headers such as x-api-key, cookie, and proxy-authorization;
  • an identity mapping rule names a jit_project_id that is not a project of the policy's organization or is not attached to the policy's gateway, sets jit_principal_cap on a pre_registered rule, or sets a principal_type other than external on a jit rule;
  • the gateway already carries four enabled policies, or another enabled policy names the same issuer.

An unrelated update does not recheck an unchanged stored value, so an existing policy keeps working. An enabled policy that still reads its token from a header the gateway cannot strip produces the warning gateway auth policy reads its token from a header the gateway cannot keep for verification and remove before the upstream in the data plane and management plane logs; move each policy it names to x-tars-idp-token or another dedicated header.

The project OIDC contract has one refusal of its own: the management plane reads the issuer's discovery document when the contract is written, and refuses an issuer on a loopback, link-local, private, carrier-grade NAT, unique-local, or otherwise non-public address. An identity provider inside the organization's own network, such as a Keycloak install, needs OIDC_DISCOVERY_ALLOW_PRIVATE_ADDRESSES=true on the management plane before its contract is written.

Upgrading a data plane that carries a policy​

Upgrade the management plane before the data planes. From 0.7.0 the data plane removes x-tars-idp-token and every other identity header it sets from the requests a caller sends, and a data plane upgraded ahead of its management plane removes that header before the gateway can verify it on a gateway with an existing policy. The data plane upgrade guide covers the order; the headers the data plane strips are listed under request normalization.