For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.
Backend authentication
Attach the gateway’s own credential to requests that it forwards to a backend.
Backend authentication is how the gateway proves its own identity to an upstream service. Client authentication is the opposite direction: how a client proves its identity to the gateway. The two are separate settings, and most routes need both.
A request therefore carries up to two credentials at different points in its life. The client sends one to the gateway, and the gateway sends a different one to the backend. What connects them is that the client credential is often what the gateway uses to get the backend credential.
Choose a method
Start from what the upstream expects, not from what the client sends.
| The upstream expects | Use | Where the credential comes from |
|---|---|---|
| A fixed API key or token | Static key | A value that you configure, or a Secret or file that you control |
| The credential that the client already sent | Passthrough | The incoming request |
| A token issued by AWS, Azure, or Google Cloud | Cloud provider credentials | The cloud provider, in exchange for the gateway’s own identity |
| A GitHub Copilot token | Cloud provider credentials | The environment of the gateway process |
| A JWT signed by your private key, fresh on every request | Signed JWT | The gateway signs one per request from a key that you supply |
| A narrower token, derived from the client’s credential at one authorization server | OAuth token exchange | An authorization server, in exchange for the client credential |
| A token from an authorization server that did not authenticate the user | Cross App Access | Two authorization servers, across a trust boundary |
The families in more detail:
- Static key. The simplest case, and the right one whenever the backend issues you a long-lived credential. Prefer a Secret or a file over an inline value, so that the credential is not stored in the configuration.
- Passthrough. Sends the client credential on to the backend unchanged. Use it when the backend validates the same credential that the gateway validated, such as two services that trust the same issuer.
- Cloud provider credentials. The gateway authenticates as itself, using the identity of the workload it runs as. This is the method to reach for on a managed cluster, because it needs no stored secret: the cloud supplies the identity and the gateway exchanges it for a token. Each provider also accepts an explicit credential when the ambient identity is not the one you want.
- Signed JWT. For an upstream that rejects durable credentials outright and wants a fresh keypair-signed JWT on each call. The Snowflake SQL API is the common example.
- OAuth token exchange. Narrows or re-scopes the client’s credential. Use it when the client identity should reach the backend, but not the client’s original token, and when one authorization server can issue the new token.
- Cross App Access. Token exchange across a trust boundary, using the OAuth Identity Assertion Authorization Grant. The identity provider that authenticated the user and the authorization server that guards the resource are different parties, so the gateway performs two exchanges and holds a client registration at each. For a single-leg exchange, use OAuth token exchange instead.
Two methods are not available everywhere. GitHub Copilot works in the standalone binary only, and Signed JWT arrived in 1.5.x. For the full matrix, see Method availability.
Combine methods
A policy sets at most one of the methods above. They are alternatives, not layers, and configuring two is rejected rather than applied in some order.
One mechanism is additive. A credentials list injects extra credentials, each to its own location, and it works either on its own or alongside a primary method. Use it for an upstream that wants two credentials on the same request, such as a bearer token and a subscription key.
Backend authentication and client authentication
The two directions interact in one way that is easy to miss: a client authentication policy removes the credential it validates.
A JWT, API key, or basic auth policy reads the client credential from a location, validates it, and then strips it from the request so the backend never sees it. That is usually what you want. It also means the credential is gone by the time backend authentication runs, which matters for two of the methods:
- Passthrough puts it back. The method exists for exactly this reason. On a route with no client authentication policy, passthrough does nothing, because nothing removed the credential in the first place.
- Token exchange and Cross App Access read the request. Both take the subject token from a location on the incoming request, defaulting to the
Authorizationheader with aBearerprefix. If a client authentication policy on the same route has already stripped that header, the exchange finds nothing to exchange.
Warning
Do not point a client authentication policy and a token exchange at the same location. The JWT policy validates the token and strips it, the exchange then has no subject token, and the request fails with a 400 and a body of invalid request. The policy status looks healthy, and the reason appears only in the gateway log at debug level.
debug http::auth::oauth oauth token exchange subject token missing source=Header { name: "authorization", prefix: Some("Bearer ") }Any of the following fixes it.
- Read the validated token instead of the header. Set the exchange’s
subjectToken.source.expressionto thejwt.rawToken.unredacted()CEL expression, which reads the token from the JWT policy’s own result rather than from the request. - Move one of the two locations. Read the client credential from a different header in the client authentication policy, or point
subjectToken.sourceat wherever the credential actually is. - Keep the credential in place. Set
preserveToken: trueon the client authentication policy so that it leaves the validated token where it found it, and the exchange reads it as usual. The token then stays in the request for every policy that runs later, so prefer one of the other two options when only the exchange needs it.
The other methods do not read the client credential at all, so they compose with any client authentication policy without further thought.
Backend authentication is not authorization
Backend authentication decides what credential the gateway sends. It does not decide who is allowed through. A route that attaches a static key to every backend request still forwards every request that reaches it.
To decide which callers are allowed, and which tools or models they may reach, use an authorization policy alongside backend authentication. The two are complementary: authorization runs on the way in, backend authentication on the way out.
Configure backend authentication
In Kubernetes, backend authentication is the auth field of a backend policy. Three resources carry it, and they are not interchangeable.
# Attach a policy to a backend, a route, or a gateway.
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayPolicy
spec:
targetRefs:
- group: agentgateway.dev
kind: AgentgatewayBackend
name: my-backend
backend:
auth:
secretRef:
name: my-credentials
---
# Or set the credential inline on the backend that uses it.
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayBackend
spec:
policies:
auth:
secretRef:
name: my-credentials| Resource | Field | Methods available |
|---|---|---|
| AgentgatewayPolicy | spec.backend.auth | All methods. |
| AgentgatewayBackend | spec.policies.auth | All methods. |
| AgentgatewayModel | spec.policies.auth | All methods except crossAppAccess and jwtSign. |
Choose the AgentgatewayPolicy resource when one credential serves several backends, or when you want to attach the credential higher up, such as to a route or a gateway. Choose the inline spec.policies.auth field when the credential belongs to exactly one backend or model. For how the controller resolves a policy that targets more than one level, see Targeting and merging.
Important
A policy that targets an AgentgatewayBackend takes effect only if a route forwards traffic to that backend. If no route does, the policy reports Attached=False with the message Policy is not attached, and the gateway sends no credential. The backendRefs entry of the HTTPRoute must name the AgentgatewayBackend, not the Kubernetes Service behind it.
Where the credential comes from
Every method except key and passthrough reads its credential from a Kubernetes Secret, through a secretRef field. The default resolver reads a specific key from the Secret, and the key differs by method.
| Field | Keys that the resolver reads |
|---|---|
auth.secretRef | Authorization. Set secretRef.key to read a different key. |
auth.aws.secretRef | accessKey and secretKey, plus sessionToken for temporary credentials. |
auth.azure.secretRef | clientID, tenantID, and clientSecret. |
auth.gcp.secretRef | credentials.json. Set secretRef.key to read a different key. |
auth.jwtSign.signingKeyRef | signingKey. |
The Secret must be in the same namespace as the policy or backend that names it.
The cloud methods do not need a Secret at all. When you omit secretRef, the gateway uses the ambient identity of the pod that it runs in, such as a Google service account through Workload Identity on GKE, an IAM role for a service account on EKS, or an Azure workload identity on AKS. Running without a long-lived secret is the recommended setup for each cloud, and each provider page describes the resolution order that the gateway follows.
Next
Each method has its own page.
| Method | Page |
|---|---|
| Static keys, Secrets, passthrough, and extra credentials | Static keys and passthrough |
| AWS, Azure, and Google Cloud | Cloud provider credentials |
| Signed JWT | Signed JWT (jwtSign) |
| OAuth token exchange | OAuth token exchange |
| Cross App Access | Cross App Access (ID-JAG) |
For the client side of authentication, see JWT auth and API key auth. To control which callers are allowed through, see Authorization.
Method availability and field differences
The standalone binary and Kubernetes configure the same features, but they do not use the same field names, and in several places they do not use the same shape either. Expand the following section before you copy a configuration block from one mode to the other.
Compare the standalone binary and Kubernetes
Which methods each mode supports:
| Method | Standalone | Kubernetes |
|---|---|---|
| Static key | key | key or secretRef |
| Passthrough | passthrough | passthrough |
| AWS | aws | aws |
| Azure | azure | azure |
| Google Cloud | gcp | gcp |
| GitHub Copilot | copilot | Not available |
| Signed JWT | jwtSign, in 1.5.x and later | jwtSign, in 1.5.x and later |
| OAuth token exchange | oauthTokenExchange | oauthTokenExchange |
| Cross App Access | crossAppAccess | crossAppAccess |
| Extra credentials | credentials | credentials |
Where the two differ in shape:
| Concern | Standalone | Kubernetes |
|---|---|---|
| Field that holds the settings | policies.backendAuth | spec.backend.auth or spec.policies.auth |
| Static key | key.value, either inline or {file: <path>} | key, an inline string |
| Credential from a Secret | Not available. Read the value from a file instead. | secretRef |
| Credential location | Nested under the method, such as key.location | A sibling field, auth.location |
Methods that accept location | Every method that writes a credential | key, secretRef, and passthrough only |
Entry in the credentials list | location and key | location and secretRef |
| Google token type | accessToken and idToken | AccessToken and IdToken |
| Azure credential source | Nested under explicitConfig, plus an implicit and a developerImplicit method | Set directly on azure, with no developerImplicit method |
| OAuth client authentication method | clientSecretBasic, clientSecretPost, and privateKeyJwt | ClientSecretBasic, ClientSecretPost, and PrivateKeyJwt |
Signing key for jwtSign | signingKey, either the PEM text or {file: <path>} | signingKeyRef, a Secret reference |
The capitalization differences are enforced, not cosmetic. The standalone binary rejects AccessToken, and the custom resources reject accessToken. A wrong case fails validation rather than falling back to a default.
Static keys and passthrough
Send a static credential to a backend, forward the credential that the client sent, or add extra …
Cloud provider credentials
Authenticate to AWS, Azure, or Google Cloud with the gateway’s own identity.
Signed JWT (jwtSign)
Sign a short-lived JWT with your own private key on every request to a backend.
OAuth token exchange
Exchange the incoming request credential for a per-backend token at an OAuth authorization server …
Cross App Access (ID-JAG)
Call a downstream API as the authenticated end user with the OAuth Identity Assertion Authorization …