Spring Boot and KeyCloak integration

Keycloak is an open source identity and access management system which offers both administrator and account management consoles for centralized management. Users can manage their profiles and active sessions using the account management console, while administrators can configure Keycloak fully. Keycloak provides user federation, strong authentication, user management and fine-grained authorization. Refer to the article to learn about how to setup and configure Keycloak
In this article, we will learn about how to integrate Spring Boot with Keycloak using session based authentication.
You will need the following dependencies to create your maven project. The following is the complete pom.xml with explanations. You can use the IDE or Spring Initializr to bootstrap your application.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>KeyCloakIntegrationWithSpringBoot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>KeyCloakIntegrationWithSpringBoot</name>
<description>Demo project for integrating KeyCloak and Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.keycloak/keycloak-spring-boot-starter -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>15.0.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Application Configuration
keycloak.realm=blackslate
keycloak.auth-server-url=http://localhost:8080
keycloak.resource=blackslate-client
keycloak.credentials.secret=xxxxxxxxxxxx
keycloak.use-resource-role-mappings=true
server.port=8084
Where,
- Realm: It is the name of the realm we created in Keycloak
- Auth-server-url: Refers to the URL of the keycloak server
- resource : refers to the client-id which is blackslate in our case
- credentials.secret: Can be found at Clients-> blackslate-client -> Credentials like in the image below
KeycloakController.java
package com.keycloak.application.controller;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.keycloak.representations.AccessToken;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
@RestController
public class KeyCloakController {
@GetMapping("/login")
public String login() {
return "Welcome to the login page";
}
@GetMapping("/homepage")
public String homepage(Principal principal) {
KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) principal;
AccessToken accessToken = token.getAccount().getKeycloakSecurityContext().getToken();
return "Welcome to the homepage, " +accessToken.getPreferredUsername()+" successfully logged in";
}
}
The login page will be accessible without authentication, while the homepage will require authentication.
Keycloak authentication token is used to read username from Keycloak and display it
KeycloakSecurity.java
package com.keycloak.application.security;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@Configuration
public class KeycloakSecurity extends KeycloakWebSecurityConfigurerAdapter {
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(
new SessionRegistryImpl());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/homepage").hasRole("user")
.anyRequest().permitAll();
http.csrf().disable();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, KeycloakAuthenticationProvider keycloakAuthenticationProvider) {
auth.authenticationProvider(keycloakAuthenticationProvider);
}
}
The above code extends the KeycloakWebSecurityConfigurerAdapter
class and overrides methods to set up authentication and authorization. It defines a session authentication strategy using the RegisterSessionAuthenticationStrategy
, specifies access rules for different endpoints (allowing access to "/homepage" only for users with the "user" role), and disables CSRF protection. Additionally, it injects a KeycloakAuthenticationProvider
into the authentication manager to handle authentication using Keycloak.
KeyCloakConfigurationResolver.java
package com.keycloak.application.security;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class KeycloakConfigurationResolver {
@Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
The above code provides a configuration class for resolving Keycloak configurations in a Spring Boot application. It declares a bean named KeycloakConfigResolver
of type KeycloakSpringBootConfigResolver
, which is a class provided by the Keycloak Spring Boot Starter to resolve Keycloak configurations specifically for Spring Boot. This bean is responsible for resolving the Keycloak configuration during the application startup, ensuring proper integration between the Spring Boot application and the Keycloak identity and access management system.
KeyCloakAuthenticationConfig.java
package com.keycloak.application.security;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
@Configuration
public class KeyCloakAuthenticationConfig {
@Bean
public KeycloakAuthenticationProvider keycloakAuthenticationProvider() {
KeycloakAuthenticationProvider provider = new KeycloakAuthenticationProvider();
provider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
return provider;
}
}
The above code defines a configuration class for setting up the Keycloak authentication provider in a Spring Boot application. It declares a bean named keycloakAuthenticationProvider
of type KeycloakAuthenticationProvider
and configures it by setting a SimpleAuthorityMapper
as the granted authorities mapper. The KeycloakAuthenticationProvider
is a component provided by the Keycloak Spring Security integration to handle authentication within the Spring Security framework. The SimpleAuthorityMapper
is used to map Keycloak roles to Spring Security authorities. This configuration ensures that Keycloak authentication is properly configured with the specified authority mapping in the Spring Boot application.
Demo ScreenShots
Start the application and go to login screen
There is no need for authentication or authorization.
Try to access homepage, which requires users to have roles - user
and to be authenticated. localhost:8084/homepage
automatically redirects to keycloak login when we try it where we have to enter the credentials
We can see the following message once we have successfully logged in:
Now let's test whether the application works with the role by unassigning the "user" role from my-first-user's keycloak.
Once we click that unassign button we would get a warning message, Are you sure want to remove that role? click yes and you would be landed in below page
As a result, when we try to access the homepage, we no longer see the successfully logged in message and instead we would see a error page
Conclusion
In this article, we explained what KeyCloak is and how it can be integrated with Spring Boot using an example.