Keycloak and Kong, when paired, transform into an incredibly powerful and flexible API gateway solution, primarily by offloading authentication and authorization concerns from your individual microservices.

Let’s see it in action. Imagine a simple API service running on http://my-api.local:8080. We want to protect this API so only authenticated users with a specific role can access it.

First, in Keycloak, we’d set up a realm (e.g., myrealm), a client for Kong (e.g., kong-gateway), and a user with a role (e.g., user alice with role api-user).

Now, in Kong, we’ll configure a route that matches requests to our API. This route will have an authentication plugin enabled. The most common setup uses the oauth2-introspection or jwt plugin, depending on how Keycloak is configured to issue tokens. Let’s assume we’re using JWT for this example.

Here’s a snippet of what a Kong declarative configuration might look like for this:

_format_version: "1.1"
services:
  - name: my-api-service
    url: http://my-api.local:8080
    routes:
      - name: my-api-route
        paths:
          - /v1/data
        plugins:
          - name: jwt
            config:
              run_on: first_by_route
              key_jwt_signing_method: HS256 # Or RS256 if using Keycloak's public key
              # If using HS256, this would be the shared secret from Keycloak
              # key_jwt_secret: "your-super-secret-key-from-keycloak"
              # If using RS256, you'd configure JWKS URL to fetch public keys from Keycloak
              # key_jwt_jwks_uri: "http://keycloak.local:8080/realms/myrealm/protocol/openid-connect/certs"
              # This plugin will validate the JWT. If valid, it injects claims.
              # We then need another plugin to authorize based on those claims.
          - name: acl
            config:
              # This plugin typically runs *after* JWT validation.
              # It checks for a specific claim (e.g., 'realm_access.roles')
              # and allows access only if the role 'api-user' is present.
              # The exact claim name depends on Keycloak's token mapper configuration.
              # For JWT, it's often 'roles' or 'realm_access.roles'.
              # For introspection, it's often injected as a header.
              allow_any: false
              roles:
                - api-user # This refers to the role name that Keycloak injects into the token claims.

consumers: [] # Consumers are typically for API key authentication, not directly for OAuth2/JWT validation at gateway level.

When alice requests http://kong.local/v1/data with a valid JWT issued by Keycloak, Kong’s jwt plugin verifies the signature and expiry. If successful, it passes the request to the acl plugin. The acl plugin inspects the claims within the JWT (e.g., alice’s roles) and, finding api-user, allows the request to proceed to http://my-api.local:8080. If alice didn’t have the api-user role, the acl plugin would deny access.

This architecture decouples your backend services from the complexities of OAuth2, OpenID Connect, and JWT management. Your microservices simply trust that requests arriving at their http://my-api.local:8080 endpoint have already been authenticated and authorized by Kong. They might then inspect additional claims passed as headers by Kong for fine-grained internal authorization if needed, but the heavy lifting is done at the gateway.

The problem this solves is the proliferation of "reinvented wheels" for authentication within each microservice. Instead of every service implementing its own JWT validation, token introspection, or session management, Kong acts as a centralized, high-performance enforcement point. This significantly reduces development effort, improves security posture by having a single point of audited authentication logic, and allows for easier management of user access policies. Keycloak handles the user identity management, issuing tokens, and defining roles, while Kong enforces the consumption of these tokens at the API gateway level.

One of the most subtle yet powerful aspects of this setup is how Kong’s plugin chaining works. When you configure multiple plugins on a single route, Kong executes them in a defined order. The jwt plugin, for example, validates the token and can inject claims into the request context. The acl plugin then reads these injected claims to make its authorization decision. This means the output of one plugin becomes the input for another, creating a sophisticated pipeline for request processing and security enforcement without custom code in your backend services. You can even add a request-transformer plugin to add custom headers based on the JWT claims, forwarding specific user attributes to your backend, or a rate-limiting plugin that applies different limits based on user roles.

The next step in this journey is often integrating with Keycloak’s user federation capabilities to manage users from external identity providers like Active Directory or LDAP, or exploring more advanced authorization scenarios using Keycloak’s fine-grained authorization services.

Want structured learning?

Take the full Keycloak course →