When building secure modern applications, developers need to rely on proven identity and access management (IAM) solutions rather than reinventing the wheel. Keycloak, an open-source identity and access management server backed by Red Hat, is one of the most popular solutions for implementing single sign-on (SSO), social login, and federated identity management.

Spring Security, on the other hand, is the de facto security framework in the Spring ecosystem, offering comprehensive support for authentication and authorization. By integrating Keycloak with Spring Security using OpenID Connect (OIDC), we can leverage centralized authentication, fine-grained role management, and OAuth 2.0 standards without writing custom authentication code.

This article provides a step-by-step guide to integrating Spring Security with Keycloak using OpenID Connect. We will cover essential configuration, dependencies, and coding examples that make the integration seamless.

Understanding Keycloak and OpenID Connect

Before diving into the integration, let’s briefly explore the core technologies involved:

  • Keycloak: Provides identity brokering, user federation, SSO, and token-based authentication. It supports OAuth 2.0, OpenID Connect (OIDC), and SAML protocols.

  • OpenID Connect (OIDC): A simple identity layer on top of OAuth 2.0. It allows applications to authenticate users via an Authorization Server (Keycloak in our case) and obtain identity information in the form of ID tokens.

  • Spring Security: A security framework that supports authentication and authorization mechanisms, including first-class integration with OAuth 2.0 and OIDC providers.

By combining these three, we can delegate authentication to Keycloak while controlling authorization inside our Spring Boot application.

Setting Up Keycloak

To begin, you need a running Keycloak server. You can quickly start one using Docker:

docker run -d \
--name keycloak \
-p 8080:8080 \
quay.io/keycloak/keycloak:24.0.2 \
start-dev

After Keycloak is running:

  1. Navigate to http://localhost:8080.

  2. Log in to the Keycloak Admin Console.

  3. Create a realm (e.g., spring-oidc).

  4. Create a client (e.g., spring-client) with the following settings:

    • Client Protocol: openid-connect

    • Access Type: confidential

    • Redirect URI: http://localhost:8081/login/oauth2/code/*

    • Valid Redirect URIs must match your Spring Boot app’s callback URL.

  5. Generate a client secret for your client.

You now have the realm, client, and credentials required for Spring Boot integration.

Adding Dependencies to Spring Boot

Create a new Spring Boot project (via Spring Initializr) with the following dependencies:

  • Spring Web

  • Spring Security

  • OAuth2 Client

  • Spring Boot Actuator (optional for monitoring)

In pom.xml:

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
</dependencies>

This ensures your application can authenticate users via OIDC and validate tokens.

Configuring Application Properties

Add the Keycloak configuration inside application.yml (or application.properties).

server:
port: 8081
spring:

security:
oauth2:
client:
registration:
keycloak:
client-id: spring-client
client-secret: YOUR_CLIENT_SECRET
scope: openid,profile,email
authorization-grant-type: authorization_code
redirect-uri: “{baseUrl}/login/oauth2/code/{registrationId}”
provider:
keycloak:
issuer-uri: http://localhost:8080/realms/spring-oidc
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/spring-oidc
  • issuer-uri points to your Keycloak realm.

  • client-id and client-secret come from the Keycloak admin console.

  • Spring Boot automatically configures OAuth2 login flows when this is set.

Creating a Security Configuration

Spring Boot 3+ uses a lambda-based SecurityFilterChain instead of the older WebSecurityConfigurerAdapter. Here’s how you configure security:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration

public class SecurityConfig {@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers(“/”, “/public”).permitAll()
.anyRequest().authenticated()
)
.oauth2Login()
.and()
.oauth2ResourceServer(oauth2 -> oauth2.jwt());return http.build();
}
}
  • / and /public are accessible without login.

  • All other routes require authentication.

  • .oauth2Login() enables OIDC login using Keycloak.

  • .oauth2ResourceServer() enables JWT validation for API endpoints.

Creating a Simple Controller

Now let’s test authentication by creating a controller.

import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController

public class DemoController {@GetMapping(“/”)
public String home() {
return “Welcome to the public page!”;
}@GetMapping(“/secure”)
public String secure(@AuthenticationPrincipal OidcUser oidcUser) {
return “Hello, “ + oidcUser.getFullName() + “! Your email is: “ + oidcUser.getEmail();
}
}

If you access /secure, you will be redirected to Keycloak’s login page. After successful login, you’ll see your name and email extracted from the ID token.

Extracting Roles from Keycloak

By default, Keycloak provides roles inside the token. To use them in Spring Security, configure Keycloak to include roles in the access token under realm_access.roles.

In application.yml, you can map these roles:

spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/spring-oidc
jwtAuthenticationConverter: customJwtAuthenticationConverter

Define a custom converter to extract roles:

import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import java.util.Collection;public class KeycloakJwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> {private final JwtGrantedAuthoritiesConverter defaultConverter = new JwtGrantedAuthoritiesConverter();
@Override
public AbstractAuthenticationToken convert(Jwt jwt) {
Collection<GrantedAuthority> authorities = defaultConverter.convert(jwt);var realmRoles = (Collection<String>) ((Map<String, Object>) jwt.getClaim(“realm_access”))
.get(“roles”);if (realmRoles != null) {
authorities.addAll(
realmRoles.stream()
.map(role -> “ROLE_” + role.toUpperCase())
.map(SimpleGrantedAuthority::new)
.toList()
);
}return new JwtAuthenticationToken(jwt, authorities);
}
}

And update the SecurityConfig:

.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt ->
jwt.jwtAuthenticationConverter(new KeycloakJwtAuthenticationConverter())
));

Now you can protect endpoints with role-based access control:

@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')")
public String adminPage() {
return "Only admins can access this page!";
}

Logging Out from Keycloak

OIDC logout can be integrated with Spring Security. Keycloak supports a logout endpoint like:

http://localhost:8080/realms/spring-oidc/protocol/openid-connect/logout

You can redirect users there after logging out in your Spring Boot app:

import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class KeycloakLogoutHandler implements LogoutSuccessHandler {

@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication)
throws IOException {

String redirectUri = “http://localhost:8081/”;
response.sendRedirect(“http://localhost:8080/realms/spring-oidc/protocol/openid-connect/logout?redirect_uri=” + redirectUri);
}
}

Register it in SecurityConfig:

.logout(logout -> logout.logoutSuccessHandler(new KeycloakLogoutHandler()))

Testing the Integration

  1. Start Keycloak and configure the realm and client.

  2. Run your Spring Boot application.

  3. Visit http://localhost:8081/secure.

  4. You should be redirected to Keycloak’s login page.

  5. After successful login, you’re redirected back with your profile details.

  6. Test /admin with a user who has the ADMIN role.

Conclusion

Integrating Spring Security with Keycloak using OpenID Connect provides a robust and standards-based approach to application security. By delegating authentication to Keycloak, you gain:

  • Centralized Authentication: Manage users, roles, and policies in Keycloak rather than scattered across applications.

  • Single Sign-On (SSO): Users log in once and access multiple applications.

  • Standards Compliance: Built on OAuth 2.0 and OpenID Connect, making it interoperable with other providers.

  • Role-Based Access Control (RBAC): Easily enforce authorization rules based on Keycloak roles.

  • Scalability: Keycloak supports clustering and integration with external identity providers (LDAP, Active Directory, social logins).

From a development perspective, Spring Security abstracts much of the OAuth2/OIDC complexity, while Keycloak handles the heavy lifting of identity management. This combination ensures your applications are not only secure but also maintainable and future-proof.

Whether you are building REST APIs, web applications, or microservices, this integration pattern sets a solid foundation for enterprise-grade security in the Spring ecosystem.