NoviForge

Keycloak in Production: IAM for Enterprise Applications

IAMKeycloakSecurity

Keycloak is an open-source Identity and Access Management (IAM) solution maintained by Red Hat. It provides Single Sign-On (SSO), OAuth 2.0, OpenID Connect (OIDC), and SAML 2.0 out of the box — making it one of the most capable self-hosted IAM platforms available.

Core concepts

Before diving into configuration, it helps to understand the key building blocks:

Concept Description
Realm An isolated namespace for users, clients, and policies
Client An application that delegates authentication to Keycloak
User A person or service account managed within a realm
Role A named permission assigned to users or clients
Identity Provider An external IdP (e.g. Active Directory, Google) federated into the realm

Deploying on Kubernetes

Keycloak ships with an official Kubernetes Operator. A minimal production-ready deployment:

apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
  name: keycloak
  namespace: iam
spec:
  instances: 3                    # HA: 3 pods, Infinispan cache clustering
  db:
    vendor: postgres
    host: postgres.iam.svc
    database: keycloak
    usernameSecret:
      name: keycloak-db-secret
      key: username
    passwordSecret:
      name: keycloak-db-secret
      key: password
  http:
    tlsSecret: keycloak-tls
  hostname:
    hostname: sso.example.internal
  features:
    enabled:
      - token-exchange
      - admin-fine-grained-authz

Keycloak uses Infinispan for distributed session and token caching across instances. With three replicas, the cluster can tolerate the loss of one node without session loss.

Configuring an OIDC client

For a backend API that validates JWTs issued by Keycloak:

{
  "clientId": "orders-api",
  "protocol": "openid-connect",
  "publicClient": false,
  "bearerOnly": true,
  "attributes": {
    "access.token.lifespan": "300"
  }
}

A frontend SPA uses the Authorization Code flow with PKCE:

{
  "clientId": "orders-spa",
  "protocol": "openid-connect",
  "publicClient": true,
  "redirectUris": ["https://app.example.internal/*"],
  "webOrigins": ["https://app.example.internal"],
  "attributes": {
    "pkce.code.challenge.method": "S256"
  }
}

Token validation in a Java backend

Using the Keycloak Spring Boot adapter (or any JOSE library):

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/actuator/health").permitAll()
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> jwt
                    .jwkSetUri("https://sso.example.internal/realms/prod/protocol/openid-connect/certs")
                )
            );
        return http.build();
    }
}

The jwk-set-uri endpoint is served by Keycloak — the backend fetches the public keys and validates the JWT signature locally, without a round-trip to Keycloak on every request.

User federation with Active Directory

Keycloak can sync users from an LDAP/Active Directory directory:

Keycloak realm → User Federation → LDAP provider
  host: ldap.corp.example.internal:636 (LDAPS)
  bindDn: CN=keycloak-svc,OU=ServiceAccounts,DC=corp,DC=example,DC=internal
  usersDn: OU=Users,DC=corp,DC=example,DC=internal
  searchScope: SUBTREE
  syncPeriod: 3600   # full sync every hour

Group memberships from AD can be mapped to Keycloak roles via LDAP group mappers, so existing access control structures carry over without manual re-provisioning.


Browser / AppKeycloakSSO / OIDC / SAML3 × replicasActive DirectoryBackend APIPostgreSQL

Fine-grained authorisation with UMA 2.0

For resource-level access control (beyond simple roles), Keycloak supports User-Managed Access (UMA 2.0). Resources, scopes, and policies are managed via the Keycloak Admin API and evaluated at runtime by the backend:

# Request a permission ticket
POST /realms/prod/protocol/openid-connect/token
grant_type=urn:ietf:params:oauth:grant-type:uma-ticket
&audience=orders-api
&permission=order#read

This allows per-resource, per-user decisions without hardcoding access rules in application code — a significant advantage in multi-tenant or document-oriented systems.

← Back to Blogs