
API Gateway OIDC: Kong and Friends
Implement OIDC authentication in Kong API Gateway, covering JWT validation, JWKS caching, and upstream header propagation.
Implementing OpenID Connect (OIDC) in an API gateway like Kong requires understanding that the gateway does not authenticate the user. The Identity Provider (IdP)—such as Auth0, Okta, or Keycloak—does that. Kong’s role is strictly verification: it must confirm that a presented JSON Web Token (JWT) was signed by a trusted key and has not expired. The mechanism hinges on two operations: fetching the public key from the issuer’s JSON Web Key Set (JWKS) and caching it efficiently to avoid latency spikes on every request.
The Verification Mechanism
When a client sends a request to Kong, it includes a Bearer token in the Authorization header. Kong’s OIDC or JWT plugin extracts this token and parses its header. The header contains a kid (Key ID) field, which identifies which specific public key was used to sign the token.
Kong then checks its internal cache for the public key corresponding to that kid. If the key is present, Kong verifies the cryptographic signature of the JWT. If the signature is valid and the claims (such as exp for expiration) are within acceptable bounds, Kong considers the request authenticated. If the key is missing from the cache, Kong makes a synchronous HTTP GET request to the IdP’s JWKS endpoint. Note that the .well-known/openid-configuration endpoint is the Discovery Document, which contains the jwks_uri field; the actual JWKS endpoint is a separate URI specified in that discovery response.
This design means Kong is stateless regarding the user session. It does not store user data. It only stores the cryptographic material needed to validate tokens. This separation of concerns allows Kong to scale horizontally, but it introduces a dependency on the IdP’s availability during key fetches.
JWKS Caching and Key Rotation
The most common failure mode in OIDC integration is improper JWKS caching. If Kong fetches the JWKS on every request, the IdP becomes a bottleneck. If Kong caches the JWKS forever, it fails when the IdP rotates signing keys.
Kong’s plugins generally rely on their own TTL configuration parameters (e.g., config.jwks_cache_ttl) rather than strictly following IdP HTTP headers like Cache-Control or ETag. Administrators must configure these TTLs to balance freshness against performance. If the IdP returns a Cache-Control header, Kong may respect it if explicitly configured to do so, but the primary control mechanism is the plugin's internal TTL setting.
However, key rotation can happen outside of standard cache windows. An IdP might rotate keys due to a security incident or a scheduled maintenance window, issuing a new kid before the old cache TTL expires. To handle this, Kong must be configured to check for key changes more frequently than the JWT’s validity period, or rely on strict TTL settings that align with IdP rotation policies.
Some implementations use a background worker that periodically refreshes the JWKS, independent of request traffic. This ensures that when a new token arrives with a new kid, the key is already in the cache. If the key is not found, Kong can either reject the request (fail-closed) or fetch it synchronously (fail-open, but with latency). For high-security environments, fail-closed is preferred; for high-availability systems, a short synchronous fetch with a fallback to a stale cache might be acceptable.
Upstream Header Propagation
Authentication is only half the problem. The backend service needs to know who the user is. Kong solves this by mapping JWT claims to HTTP headers. This process, known as header propagation, transforms the cryptographic validation into actionable context for the upstream application.
Kong’s OIDC plugin allows you to specify which claims from the JWT should be added to the request headers before forwarding to the upstream service. For example, you can map the sub (subject) claim to X-User-ID, the email claim to X-User-Email, and a custom roles claim to X-User-Roles.
This mapping is not automatic. You must define the mapping in the plugin configuration. Kong strips sensitive information from the JWT payload and only includes the mapped fields. This prevents accidental leakage of internal claims. The upstream service then trusts these headers because they were validated by Kong. If the upstream service receives a request with X-User-ID, it can assume that Kong has already verified the signature and expiration of the token containing that ID. The efficiency of this process relies heavily on the performance of the underlying jwks cache, ensuring that header propagation does not incur repeated network latency for key resolution.
Configuration Walkthrough
Consider a scenario where we are using Kong Gateway with an IdP hosted at https://auth.example.com. We want to protect a service at https://api.example.com.
First, we define the Service and Route. This is standard Kong configuration.
http POST http://kong-admin:8001/services name=api-backend url=https://api.example.com
http POST http://kong-admin:8001/services/api-backend/routes name=api-route paths=/appNext, we attach the OIDC plugin to the service. The openid-connect plugin is designed for interactive login flows (Authorization Code Flow), involving session management and redirects. It is distinct from stateless token validation.
http POST http://kong-admin:8001/services/api-backend/plugins \
name=openid-connect \
config.discovery=https://auth.example.com/.well-known/openid-configuration \
config.client_id=your-client-id \
config.client_secret=your-client-secret \
config.redirect_uris=http://localhost:8000/callbackNote that for pure JWT validation (where the client already has a token), you should use the jwt plugin instead, which is simpler and focused solely on validation.
For the jwt plugin, the configuration looks like this:
http POST http://kong-admin:8001/services/api-backend/plugins \
name=jwt \
config.claims_to_verify=exp \
config.key_claim_name=kidHere, claims_to_verify specifies which claims must be present and valid. key_claim_name tells Kong which claim in the JWT header points to the key identifier (typically kid), which Kong uses to look up the matching credential registered on a Consumer via the Admin API. Unlike the openid-connect plugin, the jwt plugin does not fetch keys from a remote JWKS endpoint.
Finally, to propagate claims, use the openid-connect plugin's built-in claim-to-header mapping, since the jwt plugin does not expose validated claims for use by other plugins like request-transformer.
http POST http://kong-admin:8001/services/api-backend/plugins \
name=openid-connect \
config.upstream_headers_claims=sub,email \
config.upstream_headers_names=X-User-ID,X-User-EmailThis configuration instructs Kong to take the value of the sub claim from the validated token and add it as a header X-User-ID to the request forwarded to api.example.com.
Tradeoffs and Operational Considerations
The primary tradeoff in this setup is complexity versus security. Implementing OIDC correctly requires managing the lifecycle of keys. If the IdP rotates keys, and Kong’s cache is stale, validation fails. Conversely, if Kong fetches the JWKS on every request, performance degrades.
Platform engineers must monitor the health of the JWKS endpoint. Kong provides metrics for the OIDC plugin, including the number of cache hits and misses. A sudden spike in cache misses indicates either a key rotation event or a misconfiguration in the TTL settings from the plugin configuration.
Additionally, consider the impact of network latency. If the IdP is in a different region, the initial JWKS fetch can add significant latency to the first request after a cache expiry. Pre-warming the cache or using a CDN to cache the JWKS endpoint can mitigate this.
Ultimately, Kong acts as a secure bridge. It validates the cryptographic integrity of the token and passes the identity context upstream. The security of the system depends on the correct configuration of this bridge, particularly the caching strategy for the public keys. Without careful management of JWKS caching, the gateway becomes either a bottleneck or a security risk.
Conclusion
Integrating OIDC with Kong involves more than just pasting a configuration; it requires a detailed understanding of key management and caching mechanics. By leveraging Kong’s ability to cache JWKS and propagate validated claims, you create a reliable, stateless authentication layer that scales horizontally while maintaining strict security boundaries. Always monitor cache hit rates and key rotation events to ensure your gateway remains both secure and performant.
Related posts
OIDC Dynamic Client Registration (RFC 7591)
A technical examination of RFC 7591, covering dynamic client registration, initial access tokens, and automated client management for backend systems.
How to Revoke a JWT: Denylist & Expiry Strategies
Learn how to revoke a JWT you already issued using denylists and token invalidation strategies for secure backend authentication.
mTLS vs JWT for Service-to-Service Auth
A comparison of mTLS and JWT for service-to-service authentication, examining transport-level security versus request-level identity in modern architectures.