Skip to content
Ashish.
All posts
Diagram illustrating the trust boundary between a client, Kong Gateway, and an Identity Provider using OIDC.

Building an Identity-Aware API Gateway with Kong and OIDC

A guide to configuring Kong Gateway with OpenID Connect for secure API authentication using JWT tokens.

By Ashish Srivastava

The core mechanism of an identity-aware API gateway is not merely checking a username and password; it is the cryptographic verification of a signed assertion that travels between a client, a gateway, and a backend. When you configure Kong Gateway with OpenID Connect (OIDC), you are architecting a system where the gateway acts as a stateless gatekeeper, trusting the signature of an Identity Provider (IdP) rather than the client's assertion of identity. This shifts the security boundary from the application logic to the protocol layer, ensuring that every request carries a verifiable chain of trust.

It is critical to distinguish between two distinct operational modes in this architecture: Gateway as Resource Server (validating pre-issued JWTs) and Gateway as OIDC Client (handling the full authentication flow). Mixing configurations from these two modes introduces security vulnerabilities and architectural contradictions. The following sections detail the correct implementation for each scenario.

The Trust Boundary Mechanism

In a standard OIDC flow, the client obtains an access token from the authorization server. This token is a JSON Web Token (JWT) signed by the IdP. The critical mechanism here is that the signature guarantees two things: the token was issued by a trusted authority and the payload has not been tampered with since issuance. When the client sends this token to the Kong Gateway, the gateway does not need to know the user's password. It only needs the public key to verify the signature.

Consider a scenario involving a frontend application named "ReactApp" and a backend microservice "OrderService". ReactApp authenticates against an IdP like Auth0 or Keycloak. Upon successful login, the IdP issues an id_token and an access_token. The access_token is what ReactApp passes to Kong. Kong, configured with the oidc plugin, intercepts this request. It does not forward the request to OrderService immediately. Instead, it performs a local validation. If the signature is invalid, the request is dropped at the network edge. If the signature is valid, Kong extracts the user identity (the sub claim) and injects it into the upstream headers. This mechanism ensures that OrderService never sees the raw authentication logic, only the verified identity context.

Kong as the Policy Enforcer

Kong Gateway functions as the policy enforcement point (PEP). Unlike a traditional firewall that filters based on IP addresses, Kong filters based on cryptographic proofs. The oidc plugin in Kong is designed to handle the discovery of the IdP's metadata automatically. When you configure the plugin, you provide the discovery endpoint URL. Kong fetches the JSON Web Key Set (JWKS) from this URL. The JWKS contains the public keys required to verify the signatures of the tokens issued by the IdP.

This caching mechanism is crucial for performance. Kong caches the JWKS locally. If the IdP rotates its signing keys, Kong polls the discovery endpoint at a configurable interval to fetch the new keys. This prevents the gateway from rejecting valid tokens during a key rotation event.

Clarification on State Management: The handling of the state parameter (as defined in RFC 6749) is specific to the Authorization Code Flow where the Gateway acts as an OIDC Client. In this scenario, the Gateway redirects the user to the IdP, receives a callback, and must ensure the state parameter matches the initial request nonce to prevent Cross-Site Request Forgery (CSRF) attacks.

However, in the standard JWT Validation scenario (where the Gateway acts as a Resource Server), the Gateway does not initiate the redirect. It simply validates a token presented by the client. Consequently, state parameter handling is not applicable in this mode. Confusing these two contexts leads to misconfiguration where client secrets are unnecessarily exposed or security parameters are applied to flows where they do not exist.

The Token Validation Pipeline

The validation pipeline inside Kong follows a strict order of operations defined by the JWT specification (RFC 7519). When a request arrives at the /orders endpoint, Kong's oidc plugin executes the following steps:

  1. Extraction: Kong looks for the token in the Authorization: Bearer <token> header.
  2. Signature Verification: Using the cached public key from the JWKS, Kong verifies the cryptographic signature. If the algorithm specified in the token header (e.g., RS256) does not match the available keys, the request fails immediately.
  3. Expiration Check: Kong checks the exp (expiration) claim. If the current time exceeds this value, the token is rejected.
  4. Audience Validation: Kong checks the aud (audience) claim to ensure the token was intended for this specific API.
  5. Claim Mapping: If all checks pass, Kong maps the sub (subject) or email claim to an upstream header, such as X-User-Id, which the backend service can read.

This pipeline ensures that the backend service receives a request that is already vetted. The backend does not need to implement its own JWT verification logic; it simply trusts the headers injected by Kong. This separation of concerns reduces the attack surface of the application code.

Configuration and State Management

To implement this, you define the plugin configuration in Kong's declarative config file or via the Admin API. It is vital to select the correct configuration profile based on your architectural role.

Scenario A: Gateway as Resource Server (JWT Validation)

In this mode, the Gateway only validates tokens issued by an IdP. It does not perform the login flow. Therefore, parameters like client_secret, client_id, and redirect_uri are not used and should be omitted.

plugins:
  - name: oidc
    config:
      # Only required parameters for JWT validation
      discovery: "https://auth.example.com/.well-known/openid-configuration"
      scopes: ["openid", "profile", "email"]
      # Optional: Define custom claim mappings
      # claims_to_verify: ["sub", "email"]
      require_https: true
      # Cache TTL for JWKS (how often to check for key rotation)
      jwks_cache_ttl: 3600

Scenario B: Gateway as OIDC Client (Full Login Flow)

If the Gateway is acting as the client to authenticate users directly (e.g., handling the redirect loop for a web application), the configuration changes significantly. In this case, client_secret and other OAuth parameters are required.

Note: Do not mix Scenario A and Scenario B parameters in a single plugin instance unless the plugin explicitly supports hybrid modes, which is rare.

plugins:
  - name: oidc
    config:
      # Required only when Gateway acts as OIDC Client
      client_id: "my-react-app-client-id"
      client_secret: "my-secret-key"
      discovery: "https://auth.example.com/.well-known/openid-configuration"
      redirect_uri: "https://app.example.com/callback"
      logout_path: "/logout"
      token_endpoint_auth_method: "client_secret_basic"
      # State parameter handling is active here to prevent CSRF
      # (Not applicable in Scenario A)

For high-availability setups, Kong clusters synchronize the JWKS cache state to ensure all nodes validate tokens consistently.

Error Handling and Fail-Safe

A critical design decision in identity-aware architectures is how the gateway behaves when the IdP is unreachable or the token validation fails. Kong defaults to a "fail-closed" mode. If the signature verification fails, or if the JWKS cannot be fetched, Kong returns a 401 Unauthorized response. This is the secure default.

However, in some legacy migration scenarios, administrators might consider a "fail-open" approach where the gateway allows traffic if the IdP is down. This is generally a dangerous opinion unless accompanied by strict rate limiting and downstream monitoring, as it effectively disables the security control. The recommended mechanism is to ensure high availability of the IdP itself. If the IdP goes down, the entire authentication system should degrade gracefully by returning a 503 Service Unavailable rather than allowing unverified traffic.

Furthermore, Kong allows for custom error responses. You can configure the plugin to return a specific JSON payload that includes the error code and a human-readable message, helping client applications diagnose whether the issue is an expired token, a bad signature, or a network connectivity problem. This transparency is essential for debugging authentication issues in distributed systems.

Conclusion

By integrating OIDC with Kong, you create an architecture where identity is a first-class citizen of the network layer. The key takeaway is the strict separation of concerns: the Gateway handles the complexity of cryptographic verification (Resource Server mode) or manages the session flow (Client mode), allowing backend services to focus on business logic while trusting the identity context provided to them. This separation ensures that your API remains secure even as the underlying user base and authentication providers evolve. Understanding whether your gateway is validating pre-issued tokens or acting as the client is the fundamental step in preventing configuration drift and security gaps.

Common Pitfalls

  1. Mixing JWT Validation with Auth Code Flow Configs: Including client_secret or redirect_uri in a configuration block meant only for validating pre-issued JWTs creates unnecessary attack surface and configuration bloat.
  2. Stale JWKS Cache: Setting the jwks_cache_ttl too high can result in the gateway rejecting valid tokens immediately after an IdP rotates its signing keys. Conversely, setting it too low increases latency and load on the IdP.
  3. Fail-Open Misconfigurations: Disabling strict validation in favor of "fail-open" behavior during IdP outages effectively bypasses the security layer, allowing unauthenticated traffic to reach your backend.

Practical Takeaways

  • Stateless by Design: Treat the Gateway as a stateless validator. Do not store session state in the Gateway; rely on the cryptographic proof within the token.
  • Separate Concerns: Explicitly decide if the Gateway is a Resource Server (validating tokens) or an OIDC Client (managing the login flow). Configure the plugin accordingly; do not blend the two.
  • Trust but Verify: While the backend trusts Kong's headers, always ensure the Gateway's JWKS source is trusted and the cache is regularly refreshed.

FAQ

Q: Do I need a client_secret if I only want Kong to validate JWTs? A: No. If the Gateway is acting as a Resource Server validating tokens issued by an external IdP, it only needs the discovery URL to fetch public keys (JWKS). client_secret is only required if the Gateway itself is acting as an OAuth Client to perform the login flow.

Q: Can I use the oidc plugin for both the login redirect and token validation in the same instance? A: Generally, no. It is best practice to separate these concerns. Use the oidc plugin in "Resource Server" mode for API endpoints and handle the redirect flow separately, or use the "Client" mode only if the Gateway is managing the entire user session lifecycle. Mixing them often leads to ambiguous configuration states.

Q: What happens if the IdP goes down and the JWKS cache expires? A: By default, Kong will fail closed and return a 503 Service Unavailable if it cannot fetch or verify keys against the cached JWKS. This prevents unauthorized access but may impact availability. High availability setups often involve multiple IdP endpoints or robust caching strategies to mitigate this.

Related posts