OpenID Connect authentication with AI Gateway 2.0

AI Gateway uses AI Auth Strategies to authenticate callers to AI Models, AI Agents, and AI MCP Servers. Depending on how you configure them, they can attribute usage to AI Consumers and reject unauthenticated requests.

With the OpenID Connect AI Auth Strategy, AI Gateway accepts the JWT bearer tokens or OAuth 2.0 grants that your AI Consumers already get from an OIDC-compliant identity provider (IdP). You don’t issue or rotate static API keys, as you would with key auth.

Use OpenID Connect when your AI Consumers already authenticate through an enterprise IdP. Use key auth when your AI Consumers are internal tools or scripts that you control. An AI Model can use both at the same time, for example key auth for internal automation and OpenID Connect for user-facing applications. A request is authenticated if it satisfies either strategy. AI Agents and AI MCP Servers accept one AI Auth Strategy each.

The strategy’s config object passes through to Kong Gateway’s OpenID Connect plugin. AI Gateway documents a subset of the plugin’s fields in the schema and accepts the rest for advanced use cases.

How it works

OpenID Connect works by forming a federation with an IdP. The IdP stores account credentials and authenticates the caller. AI Gateway trusts that authentication instead of managing credentials itself. Konnect provides Kong Identity, a managed IdP you can use for this, or you can point the AI Auth Strategy at any OIDC-compliant provider you already run.

You create an OpenID Connect AI Auth Strategy once, then attach it by name or id to one or more AI Models, AI Agents, or AI MCP Servers through their access.auth_strategies array. AI MCP Servers only accept an AI Auth Strategy in conversion-listener, listener, or passthrough-listener mode, the three modes that accept incoming MCP traffic directly. See the AI MCP Server entity for the full mode reference.

Once authenticated, a token can map to an AI Consumer, a Kong Identity principal, or both at once. See Identity mapping on the AI Auth Strategy entity for how that mapping works.

When you attach an AI Auth Strategy to an AI Model, AI Agent, or AI MCP Server, AI Gateway auto-provisions a shared anonymous AI Consumer with a Request Termination policy under the hood, and points the auth strategy’s failure path at it. By default, this means that any request that fails authentication (for example, no credential, an invalid token, or a valid token that doesn’t map to a known AI Consumer or Kong Identity principal) is routed to that anonymous AI Consumer and rejected with 401 Unauthorized before it reaches the AI Model, AI Agent, or AI MCP Server.

Two settings opt specific requests out of that default termination, without disabling it entirely:

  • config.consumer_optional: true (openid-connect only): A valid token that doesn’t map to any AI Consumer proceeds instead of terminating. The request still carries no AI Consumer identity.
  • config.principals.error_on_miss: false (key-auth and openid-connect): A request that doesn’t match any Kong Identity principal proceeds instead of terminating.

Neither setting affects a request without credentials or an invalid token, those always terminate through the anonymous AI Consumer regardless of consumer_optional or principals.error_on_miss.

The following diagram shows the three outcomes for a request against an AI Model, AI Agent, or AI MCP Server with an OpenID Connect AI Auth Strategy attached:

 
sequenceDiagram
    participant Client as AI Consumer
    participant Auth as OpenID Connect AI Auth Strategy
    participant Anon as Anonymous AI Consumer
(Request Termination) participant Entity as AI Model, AI Agent,
or AI MCP Server Client->>Auth: Request with bearer token alt Valid token, maps to a known AI Consumer Auth->>Entity: Proxies request as that AI Consumer Entity-->>Client: Response else No token, or invalid token Auth->>Anon: Routes to anonymous AI Consumer Anon-->>Client: 401 Unauthorized else Valid token, no Consumer/principal match,
consumer_optional or principals.error_on_miss set Auth->>Entity: Proxies request without an AI Consumer identity Entity-->>Client: Response end

Authorization with ACLs

Authentication and authorization are separate steps. The AI Auth Strategy only confirms who’s calling. It doesn’t decide which AI Model, AI Agent, or AI MCP Server that caller may reach. Use access.acls on the entity itself to restrict that by AI Consumer, AI Consumer Group, or Authenticated Group (a dynamic group derived from an OAuth 2.0 scope or claim in the token). This matters even when every caller shares one IdP. If several AI Models reference the same OpenID Connect AI Auth Strategy, every caller with a valid token from that IdP passes authentication on all of them. access.acls is what actually segments access to a specific AI Model, AI Agent, or AI MCP Server.

Discovery cache

When you configure config.issuer in the OIDC Auth Strategy, AI Gateway automatically retrieves the provider’s discovery metadata. The OIDC Auth Strategy stores the metadata as a discovery cache object and uses the cache to avoid repeated fetches. This cache includes the discovery document endpoints, JWKS keys, and the token endpoint.

AI Gateway uses the discovery cache whenever validation needs issuer metadata. The cache behaves in the following way:

  • The cache TTL (time-to-live) is managed by config.cache_ttl, which is set to 3600 seconds by default.
  • If a request requires discovery information that isn’t in the cache, the plugin attempts to “rediscover” it using the value in config.issuer. After a rediscovery occurs, no further rediscovery attempts are made until the time period defined in config.rediscovery_lifetime has elapsed, which helps avoid excessive requests to the identity provider.
  • If a JWT can’t be validated due to missing discovery data, and a rediscovery request returns a non‑2xx status code, the plugin falls back to using any sufficient discovery information that remains in the cache.

Supported flows and grants

Configure which flows are active with config.auth_methods. AI Gateway enables bearer and client_credentials by default. AI Gateway searches for credentials in the following order of precedence:

  1. Session authentication
  2. JWT access token authentication (bearer)
  3. Introspection authentication
  4. User info authentication
  5. Refresh token grant
  6. Password grant
  7. Client credentials grant
  8. Authorization code flow

AI Gateway stops at the first match in that order. This precedence order is the same one AI Gateway’s OpenID Connect plugin uses, since the same plugin engine runs underneath the AI Auth Strategy, and it’s fixed: it can’t be reconfigured.

Session authentication

AI Gateway can issue a session cookie after a caller first authenticates through one of the other flows. The caller then presents that cookie on subsequent requests instead of re-authenticating. For example, the authorization code flow demonstrates session authentication when it uses the redirect login action.

JWT access token authentication (bearer)

For legacy reasons, stateless JWT access token authentication is named bearer in config.auth_methods. AI Gateway verifies the token’s signature against the IdP’s published keys and validates standard claims, such as exp.

Introspection authentication

Like bearer, introspection authentication relies on a token the AI Consumer already obtained. The difference is that AI Gateway calls the IdP’s introspection endpoint to check whether the token is valid and active, which allows the IdP to issue opaque tokens instead of JWTs.

Note: Setting config.client_auth to client_secret_post lets you test the connection to your IdP, but we recommend using a more secure auth method in production. You can use any of the supported client auth methods.

User info authentication

User info authentication verifies the access token against the IdP’s standard user info endpoint, instead of the introspection endpoint. Use introspection instead in most cases, as it’s meant for validating the token itself, where user info is meant for retrieving information about the user the token was issued to.

Note: Setting config.client_auth to client_secret_post lets you test the connection to your IdP, but we recommend using a more secure auth method in production. You can use any of the supported client auth methods.

Refresh token grant

The refresh token grant can be used when the AI Consumer already has a refresh token. IdPs generally only allow the refresh token grant to run with the same client that originally obtained the token. A mismatch can cause it to fail.

Note: Setting config.client_auth to client_secret_post lets you test the connection to your IdP, but we recommend using a more secure auth method in production. You can use any of the supported client auth methods.

Password grant

Password grant is a legacy authentication grant. This is a less secure way of authenticating end users than the authorization code flow, because, for example, the passwords are shared with third parties.

Client credentials grant

AI Gateway forwards the credentials the AI Consumer passes to the IdP’s token endpoint directly, without trying to authenticate itself.

Note: Setting config.client_auth to client_secret_post lets you test the connection to your IdP, but we recommend using a more secure auth method in production. You can use any of the supported client auth methods.

Authorization code flow

The authorization code flow is a three-legged OAuth/OpenID Connect flow, including session cookie issuance. The sequence diagram below describes the participants and their interactions for this usage scenario, including the use of session cookies.

Note: Setting config.client_auth to client_secret_post lets you test the connection to your IdP, but we recommend using a more secure auth method in production. You can use any of the supported client auth methods.

If using PKCE, the IdP must include code_challenge_methods_supported in its /.well-known/openid-configuration discovery response, per RFC 8414. Otherwise, AI Gateway won’t send the PKCE code_challenge parameter.

Authorization

Beyond access.acls (see How it works), the OpenID Connect AI Auth Strategy supports claims-based authorization. Claims-based authorization uses a pair of options to manage claims verification during authorization. The pair can be any of:

  • config.scopes_claim and config.scopes_required
  • config.audience_claim and config.audience_required
  • config.groups_claim and config.groups_required
  • config.roles_claim and config.roles_required

In each parameter pair, the *_claim parameter points to a source, and the *_required parameter defines a set of claims values to check against.

Claims-based auth adheres to the following rules:

  • You can validate a maximum of 4 claims at the same time
  • You can traverse an array or object for the claim name
  • You can validate multiple values of the same claim using OR and AND logic

Both the claim type and the required claim content take an array of string elements.

Claim type

For the claim type (for example, config.groups_claim), the array is a list of JSON objects listed in nested order. AI Gateway uses the order of the items in the array to look up data in a JSON payload.

The value of a claim can be:

  • A space-separated string (common for scope claims)
  • A JSON array of strings (common for groups claims)
  • A simple value, such as a string

For example, look at the following sample payload, where groups is nested inside user:

{
    "user": {
        "name": "alex",
        "groups": [
            "employee",
            "marketing"
        ]
    }
}

In this case, use config.groups_claim to traverse to the groups you need, where groups is the JSON object that contains the list of groups:

config:
  groups_claim:
  - user
  - groups

Claim requirements

The config.*_required parameters (for example, config.groups_required) are arrays that allow logical AND/OR types of checks:

  • AND: Space-separated values. This claim has to have both employee AND marketing:

    config:
      groups_required:
      - employee marketing
  • OR: Values in separate array indices. This claim has to have either employee OR marketing:

    config:
      groups_required:
      - employee
      - marketing

This runs independently of access.acls, which authorizes an already-resolved AI Consumer identity against a specific entity.

If a claims check fails, the request goes to the anonymous AI Consumer like any other failed authentication, and the caller receives 401 Unauthorized.

Client authentication

config.client_auth selects how AI Gateway authenticates itself to the IdP, including through mutual TLS (mTLS) client authentication.

Note: Setting config.client_auth to client_secret_post lets you test the connection to your IdP, but we recommend using a more secure auth method in production. You can use any of the supported client auth methods.

Mutual TLS client authentication

The OpenID Connect auth strategy supports mutual TLS (mTLS) client authentication with the IdP. When mTLS authentication is enabled, AI Gateway establishes mTLS connections with the IdP using the configured client certificate. You can use mTLS client authentication with the following IdP endpoints and corresponding flows:

For all these endpoints and for the flows supported, the auth strategy uses mTLS client authentication as the authentication method when communicating with the IdP, for example, to fetch the token from the token endpoint.

Advanced OpenID Connect plugin capabilities

The following capabilities exist on Kong Gateway’s OpenID Connect plugin, which the OpenID Connect AI Auth Strategy’s config object passes through to for advanced use cases.

Financial-grade API (FAPI)

AI Gateway supports various features of the FAPI standard, aimed at protecting APIs that expose high-value and sensitive data.

Specification

Description

Pushed authorization requests (PAR) With PAR enabled, AI Gateway (as the OAuth client) sends the payload of an authorization request to the IdP. As a result, it obtains a request_uri value. The client uses this value in a call to the authorization endpoint as a reference to obtain the authorization request payload data.

Use config.pushed_authorization_request_endpoint to enable PAR.
JWT-secured authorization requests (JAR) With JAR enabled, when sending requests to the authorization endpoint, AI Gateway provides request parameters in a JSON Web Token (JWT) instead of using a query string. This allows for request data to be signed with JSON Web Signature (JWS).

Use config.require_signed_request_object to enable JAR.
JWT-secured authorization response mode (JARM) With JARM enabled, AI Gateway requests the authorization server to return the authorization response parameters encoded in a JWT, which allows the response data to be signed with JSON Web Signature (JWS).

Set config.response_mode to any of the following values: query.jwt, form_post.jwt, fragment.jwt, jwt to enable JARM.
Certificate-bound access tokens Certificate-bound access tokens allow binding tokens to clients. This guarantees the authenticity of the token by verifying whether the sender is authorized to use the token for accessing protected resources.

Set config.proof_of_possession_mtls to strict and config.client_id to a client bound to a client certificate to enable cert-bound access tokens.
Mutual TLS (mTLS) client authentication with certificate-bound access tokens When mTLS client authentication is enabled, AI Gateway establishes mTLS connections with the IdP using the configured X.509 certificate as client credentials.

If the authorization server is configured to bind the client certificate with the issued access token, AI Gateway can validate the access token using mTLS proof of possession.

Set config.client_auth to tls_client_auth and provide a certificate at config.tls_client_auth_cert_id to enable mTLS auth.
Demonstrating proof-of-possession (DPoP) Demonstrating Proof of Possession (DPoP) is an application-level mechanism for proving the sender’s ownership of OAuth access and refresh tokens. With DPoP, a client can prove possession of a public/private key pair associated with a token by using a header. The header contains a signed JWT that includes a reference to the associated access token.

When DPoP is enabled, AI Gateway validates the DPoP header in the request to ensure that the sender is authorized to use the access token.

Set config.proof_of_possession_dpop to strict to enable DPoP.

Certificate-bound access tokens

One of the main vulnerabilities of OAuth is bearer tokens. With OAuth, presenting a valid bearer token is enough proof to access a resource. This can create problems, since the client presenting the token isn’t validated as the legitimate user the token was issued to.

Certificate-bound access tokens solve this problem by binding tokens to clients. This ensures the legitimacy of the token, because it requires proof that the sender is authorized to use a particular token to access protected resources.

Certificate-bound access tokens are supported by the following auth methods:

Session authentication is only compatible with certificate-bound access tokens when used along with one of the other supported authentication methods:

  • When config.proof_of_possession_auth_methods_validation is set to false and other non-compatible methods are enabled, and a valid session is found, AI Gateway only performs the proof of possession validation if the session was originally created using one of the compatible methods.
  • If you configure multiple OpenID Connect auth strategy instances with the session auth method, configure a different config.session_secret value on each for additional security. This avoids sessions being shared across auth strategy instances and possibly bypassing the proof of possession validation.

To enable certificate-bound access tokens:

  • Ensure that the IdP you’re using is set up to generate OAuth 2.0 mutual TLS certificate-bound access tokens.
  • Use config.proof_of_possession_mtls to verify that the supplied access token belongs to the client, by checking its binding with the client certificate provided in the request.

The following is an example cert-bound access token config:

kongctl apply -f - --auto-approve --pat "$KONNECT_TOKEN" << 'EOF'
ai_gateway_auth_strategies:
  - ref: cert-bound-auth
    ai_gateway: !lookup {id: !env AI_GATEWAY_ID}
    display_name: Cert-Bound Access Tokens Auth
    name: cert-bound-auth
    type: openid-connect
    config:
      issuer: https://dev-123456.okta.com
      client_id:
      - my-client-id
      client_secret:
      - !secret {source: !env 'CLIENT_SECRET'}
      auth_methods:
      - bearer
      proof_of_possession_mtls: strict
      consumer_claims:
      - - sub
      cache_tokens_salt: cert-bound-auth-cache-salt
EOF

Demonstrating Proof-of-Possession (DPoP)

Demonstrating Proof-of-Possession (DPoP) is an alternative technique to mutual TLS client authentication with certificate-bound access tokens. Unlike mTLS, which binds the token to the mTLS client certificate, DPoP binds the token to a JSON Web Key (JWK) provided by the client.

 
sequenceDiagram
    autonumber
    participant client as Client 
(e.g. mobile app) participant kong as Gateway participant upstream as Upstream
(backend service,
e.g. httpbin) participant idp as Authentication Server
(e.g. Keycloak) activate client client->>client: generate key pair client->>idp: POST /oauth2/token
DPoP:$PROOF deactivate client activate idp idp-->>client: DPoP bound access token ($AT) activate client deactivate idp client->>kong: GET https://example.com/resource
Authorization: DPoP $AT
DPoP: $PROOF activate kong deactivate client kong->>kong: validate $AT and $PROOF kong->>upstream: proxied request
GET https://example.com/resource
Authorization: Bearer $AT deactivate kong activate upstream upstream-->>kong: upstream response deactivate upstream activate kong kong-->>client: response deactivate kong

You can use DPoP without mTLS, and even with plain HTTP, although HTTPS is recommended for enhanced security.

When verification of the DPoP proof is enabled, AI Gateway removes the DPoP header and changes the token type from dpop to bearer. This effectively downgrades the request to use a conventional bearer token, and lets an upstream without DPoP support work with the DPoP token without losing the protection of the key binding mechanism.

DPoP is compatible with the following authentication methods:

Session authentication is only compatible with DPoP when used along with one of the other supported authentication methods. If you configure multiple OpenID Connect auth strategy instances with the session authentication method, configure a different config.session_secret value on each for additional security. This avoids sessions being shared across auth strategy instances and possibly bypassing the proof of possession validation.

To enable DPoP:

  • Ensure that the IdP you’re using has DPoP enabled.
  • Use config.proof_of_possession_dpop to verify that the supplied access token is bound to the client, by checking its association with the JWT provided in the request.

The following is an example DPoP config:

kongctl apply -f - --auto-approve --pat "$KONNECT_TOKEN" << 'EOF'
ai_gateway_auth_strategies:
  - ref: dpop-auth
    ai_gateway: !lookup {id: !env AI_GATEWAY_ID}
    display_name: DPoP Auth
    name: dpop-auth
    type: openid-connect
    config:
      issuer: https://dev-123456.okta.com
      client_id:
      - my-client-id
      client_secret:
      - !secret {source: !env 'CLIENT_SECRET'}
      auth_methods:
      - bearer
      proof_of_possession_dpop: strict
      consumer_claims:
      - - sub
      cache_tokens_salt: dpop-auth-cache-salt
EOF

Multi-IdP support

If your APIs serve clients that authenticate with different identity providers, the OIDC auth strategy can validate tokens from multiple issuers at the gateway layer, so backends don’t need per-IdP logic.

You can implement this in one of the following ways:

  • Trusted issuers registry: Configure the OIDC auth strategy with a list of trusted issuers and their JWKS endpoints using config.issuers_allowed and config.extra_jwks_uris. AI Gateway validates incoming tokens against the appropriate public keys and forwards them to the backend as-is. This works best when token formats are consistent across IdPs.

  • Token exchange: Configure the OIDC auth strategy to swap incoming tokens for a canonical token from one trusted issuer using config.token_exchange. The backend always receives tokens from a single issuer regardless of which IdP the client used. This works best when backends must trust one issuer, or when you need to normalize scopes and claims across IdPs.

Token exchange

The OAuth 2.0 Token Exchange (RFC 8693) is an extension to the OAuth 2.0 framework that allows exchanging an existing security token for a new one. The RFC defines a protocol approach to support scenarios where a client can exchange a token for a new token by interacting with the authorization server. This is particularly useful in complex environments like microservices or cross-domain federations.

Note: Only access tokens can be exchanged with the OIDC auth strategy. Token exchange isn’t supported on AI MCP Servers that set access.metadata.

Why use token exchange?

Token exchange can be used in several critical use cases:

  • Downscoping: A service receives a powerful token but only needs a subset of those permissions to call an upstream service. It exchanges the powerful token for one with fewer scopes to maintain the Principle of Least Privilege.
  • Internal vs. external tokens: Converting an external opaque token or a third-party token (like a SAML assertion) into an internal JWT that the microservices understand.
  • Impersonation and delegation: Allowing a service to act on behalf of a user. For example, a frontend service needs to trade its token for a new token with specific scopes to call a backend service.
  • Privacy: Removing sensitive user information from a token before passing it to an upstream service.

Because token exchange allows for the creation of new tokens, trust models are vital. The trust model must strictly define which clients are allowed to exchange tokens and which scopes they are permitted to elevate or downgrade to prevent security flaws like privilege escalations.

How token exchange works

In a typical OAuth flow, a token is obtained to access a resource. However, in a token exchange, a client already has a token (the “subject token”). AI Gateway decides which incoming tokens are eligible for exchange and facilitates the token exchange using its own client credentials. The subject token is presented to the authorization server to get a different token (the “requested token”) that is better suited for accessing the resource.

 
sequenceDiagram
    participant C as Client
(e.g. mobile app) participant K as Gateway participant A as Authorization server
(e.g. Keycloak) participant U as Upstream
(backend service,
e.g. httpbin) C->>K: Request with subject token activate K note over K: Validate subject token
(iss, exp, nbf) K->>A: Token exchange request activate A A-->>K: Exchanged access token deactivate A K->>K: Validate exchanged token K->>U: Proxy request with exchanged token activate U U-->>K: Response deactivate U K-->>C: Response deactivate K

Before triggering the exchange, the OIDC auth strategy performs the following checks on the incoming token:

  1. Checks the incoming subject token meets the following criteria:
    • The issuer (iss claim) matches a configured trusted issuer (subject_token_issuers).
    • The token is not expired (exp claim).
    • The token is not used before its time (nbf claim).
  2. If the subject_token_issuer and target_issuer are different, token exchange is triggered.
  3. If the subject_token_issuer and target_issuer are the same, the configured conditions are evaluated to determine whether to trigger token exchange.
  4. AI Gateway uses its client credentials to trigger the exchange.

Afterwards, the OIDC auth strategy continues processing the exchanged token through the rest of its flow.

Depending on the use case, AI Gateway can exchange the token either with the same authorization server that issued the initial subject token, or exchange tokens between different authorization servers.

Key terms

The token exchange flow uses the following terms:

  • Subject token: The input token representing the identity/authorization being exchanged.
  • Subject token issuer: The authorization server that issued the initial token (subject token).
  • Target issuer: The authorization server protecting the resources (APIs/services).
  • Conditions: Conditions under which to trigger token exchange. Conditions look for the presence or absence of two claims: scopes and audience.

The following is an example token exchange config, which exchanges tokens issued by https://keycloak.example.com for a token from the AI Auth Strategy’s own issuer, https://dev-123456.okta.com, before proxying the request upstream:

kongctl apply -f - --auto-approve --pat "$KONNECT_TOKEN" << 'EOF'
ai_gateway_auth_strategies:
  - ref: token-exchange-auth
    ai_gateway: !lookup {id: !env AI_GATEWAY_ID}
    display_name: Token Exchange Auth
    name: token-exchange-auth
    type: openid-connect
    config:
      issuer: https://dev-123456.okta.com
      client_id:
      - my-client-id
      client_secret:
      - !secret {source: !env 'CLIENT_SECRET'}
      client_auth:
      - client_secret_post
      auth_methods:
      - bearer
      token_exchange:
        subject_token_issuers:
        - issuer: https://keycloak.example.com
        request:
          empty_audience: false
          scopes:
          empty_scopes: false
          audience:
      cache_tokens_salt: token-exchange-auth-cache-salt
EOF

Using cloud authentication with Redis

If you set config.session_storage to redis to store sessions for the session or authorization code flow, you can authenticate to Redis with a cloud provider. This allows you to rotate credentials without relying on static passwords.

The following providers are supported:

  • AWS ElastiCache
  • Azure Managed Redis
  • Google Cloud Memorystore (with or without Valkey)

Each provider also supports an instance and cluster configuration.

Multiple clients

config.client_id and config.client_secret are array fields on the OpenID Connect AI Auth Strategy schema, and behave the same way as on the plugin.

You can configure the OIDC auth strategy (config.client_id) and client secrets (config.client_secret), where the ID and client pairs correspond based on their locations in the array.

For example:

config:
  issuer: example-issuer-url
  client_id:
    - my-first-client
    - my-second-client
  client_secret:
    - first-client-secret
    - second-client-secret

When making a request, you can specify which client to target to use by including a client ID argument. For example, after configuring the auth strategy client secrets, you can target a client by name:

curl -X GET "http://localhost:8000?client_id=my-second-client"

Or by its index value (starting with 1):

curl -X GET "http://localhost:8000?client_id=2"

AI Gateway will look for the client ID in the following locations, in order of precedence:

  1. If config.client_arg is set, AI Gateway checks for that value in the following order: in the request header, URI argument, and body.
  2. If config.client_arg is not set, AI Gateway checks for a client_id in the following order: in the request header, URI argument, and body.
  3. If no client is found in either of those places, AI Gateway uses the first client ID and client secret pair.

Note: Configuring multiple clients is not possible with the client credentials grant, as the auth strategy always uses the client ID passed directly from the client.

Schema

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!