Skip to content
agentgateway has joined the Agentic AI FoundationLearn more

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

Page as Markdown

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 expectsUseWhere the credential comes from
A fixed API key or tokenStatic keyA value that you configure, or a Secret or file that you control
The credential that the client already sentPassthroughThe incoming request
A token issued by AWS, Azure, or Google CloudCloud provider credentialsThe cloud provider, in exchange for the gateway’s own identity
A GitHub Copilot tokenCloud provider credentialsThe environment of the gateway process
A JWT signed by your private key, fresh on every requestSigned JWTThe gateway signs one per request from a key that you supply
A narrower token, derived from the client’s credential at one authorization serverOAuth token exchangeAn authorization server, in exchange for the client credential
A token from an authorization server that did not authenticate the userCross App AccessTwo 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 Authorization header with a Bearer prefix. 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.expression to the jwt.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.source at wherever the credential actually is.
  • Keep the credential in place. Set preserveToken: true on 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 the standalone binary, backend authentication is the backendAuth policy. Attach it to one backend, or to a route so that it covers every backend on that route.

# yaml-language-server: $schema=https://agentgateway.dev/schema/config
gateways:
  default:
    port: 3000
routes:
- backends:
  - host: backend.example.com:443
    policies:
      backendAuth:
        key:
          value: $MY_API_KEY
Where you set itField
One backendroutes[].backends[].policies.backendAuth
Every backend on a routeroutes[].policies.backendAuth
The simplified MCP stylemcp.policies.backendAuth
One model in the simplified LLM stylellm.models[].auth

Note

The simplified LLM style is the one exception to the field name. A model sets auth, not backendAuth, and it takes the same settings. There is no llm.policies.backendAuth: that policy list covers requests on the way in, before a model is selected, so agentgateway rejects a backendAuth entry in it.

For how agentgateway resolves a policy that is set at more than one level, see Attachment points.

Next

Each method has its own page.

MethodPage
Static keys, passthrough, and extra credentialsStatic keys and passthrough
AWS, Azure, Google Cloud, and GitHub CopilotCloud provider credentials
Signed JWTSigned JWT
OAuth token exchangeOAuth token exchange
Cross App AccessCross App Access

For the client side of authentication, see JWT authentication, API Key authentication, and Basic authentication. To control which callers are allowed through, see HTTP authorization and MCP 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:

MethodStandaloneKubernetes
Static keykeykey or secretRef
Passthroughpassthroughpassthrough
AWSawsaws
Azureazureazure
Google Cloudgcpgcp
GitHub CopilotcopilotNot available
Signed JWTjwtSign, in 1.5.x and laterjwtSign, in 1.5.x and later
OAuth token exchangeoauthTokenExchangeoauthTokenExchange
Cross App AccesscrossAppAccesscrossAppAccess
Extra credentialscredentialscredentials

Where the two differ in shape:

ConcernStandaloneKubernetes
Field that holds the settingspolicies.backendAuthspec.backend.auth or spec.policies.auth
Static keykey.value, either inline or {file: <path>}key, an inline string
Credential from a SecretNot available. Read the value from a file instead.secretRef
Credential locationNested under the method, such as key.locationA sibling field, auth.location
Methods that accept locationEvery method that writes a credentialkey, secretRef, and passthrough only
Entry in the credentials listlocation and keylocation and secretRef
Google token typeaccessToken and idTokenAccessToken and IdToken
Azure credential sourceNested under explicitConfig, plus an implicit and a developerImplicit methodSet directly on azure, with no developerImplicit method
OAuth client authentication methodclientSecretBasic, clientSecretPost, and privateKeyJwtClientSecretBasic, ClientSecretPost, and PrivateKeyJwt
Signing key for jwtSignsigningKey, 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.

Was this page helpful?
Agentgateway assistant

Ask me anything about agentgateway configuration, features, or usage.

Note: AI-generated content might contain errors; please verify and test all returned information.

Tip: one topic per conversation gives the best results. Use the + button in the chat header to start a new conversation.

Switching topics? Starting a new conversation improves accuracy.
↑↓ navigate select esc dismiss

What could be improved?

Your feedback helps us improve assistant answers and identify docs gaps we should fix.

Need more help? Join us on Discord: https://discord.gg/y9efgEmppm

Want to use your own agent? Add the Solo MCP server to query our docs directly. Get started here: https://search.solo.io/.