OAuth2 Login with Keycloak and Spring Boot Security 3

This Spring security tutorial will explore how to use Keycloak and Spring Security OAuth2 module to implement authentication and authorization in a spring boot application. We will walk step-by-step from configuring a security realm in Keycloak server and using this realm for authentication/authorization of a REST API developed using Spring Boot 3.

1. Prerequisites

To follow this tutorial, we should have a basic understanding of the following:

  • What are authentication and authorization?
  • OAuth2 basics
  • Spring boot basics
  • Spring Security basics

2. Install and Setup Keycloak

2.1. Installation

There are several methods to install Keycloak, including:

In this article, we will use Docker to easily install and run Keycloak. We can download and start the Keycloak container by running the following commands in the terminal:

docker pull quay.io/keycloak/keycloak:latest

Run the following command starts the Keycloak container with the specified username and password for the Keycloak Administration Console. It also maps port 8180 of the container to port 8180 of the host machine.

docker run --name keycloak_server -p 8180:8180 \
		-e KEYCLOAK_ADMIN=admin \
		-e KEYCLOAK_ADMIN_PASSWORD=password \
		quay.io/keycloak/keycloak:latest \
		start-dev \
		--http-port=8180

Once the container is started, we can access the Keycloak Administration Console by opening a web browser and going to http://localhost:8180.

2.2. Setting Up a New Realm

Follow the instructions given in getting started with Keycloak for configuring the realm, users and roles. For this tutorial, we are using the following configuration:

Realm name: howtodoinjava-realm
ClientId: employee-management-api
Client Secret: <generated>
Username: test-user
Password: password
Role: USER

3. Spring Boot Configuration

In this article, we are reusing the APIs created for Vue.js application with Spring Boot. Here, Spring boot application will be modified to act as OAuth client and Keycloak will be used as authorization server.

3.2. Maven

To configure Spring Boot Security Oauth2 to use Keycloak as Identity Provider, we need to add the following Maven dependencies:

<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>

3.2. OAuth2 Client Configuration

In the application.properties file, add the following properties. We can access the property values in the “Client” section of the Keycloak admin console. Replace the client-id and client-secret values with the values for your Keycloak client. Also, replace the realm name as you configured in Keycloak.

A recommended approach is to store them as environment variables that can be accessed securely by the application at runtime. This helps to protect the client id and secret from being exposed in the source code, which could potentially lead to a security breach.

server.port=9090

spring.security.oauth2.client.registration.keycloak.client-id=employee-management-api
spring.security.oauth2.client.registration.keycloak.client-secret=--generated--
spring.security.oauth2.client.registration.keycloak.scope=openid
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.redirect-uri=http://localhost:9090/login/oauth2/code/employee-management-api
spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8180/realms/howtodoinjava-realm

The equivalent Java configuration is:

@Bean
public ClientRegistrationRepository clientRepository() {

	ClientRegistration keycloak = keycloakClientRegistration();
	return new InMemoryClientRegistrationRepository(keycloak);
}

private ClientRegistration keycloakClientRegistration() {

	return ClientRegistration.withRegistrationId("howtodoinjava-realm")
		.clientId("employee-management-api")
		.clientSecret("--generated--")
		.redirectUri("http://localhost:9090/login/oauth2/code/employee-management-api")
		.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
		.issuerUri("http://localhost:8180/realms/howtodoinjava-realm")
		.authorizationUri("http://localhost:8080/realms/howtodoinjava/protocol/openid-connect/auth")
		.tokenUri("http://localhost:8180/realms/howtodoinjava/protocol/openid-connect/token")
		.userInfoUri("http://localhost:8180/realms/howtodoinjava/protocol/openid-connect/userinfo")
		.build();
}

After detecting these properties, Spring boot auto-configuration will set up the necessary components to enable authentication/authorization with Keycloak (using OAuth2ClientAutoConfiguration class ).

5.3. Spring Security

Currently, Spring Security still uses the default authentication workflow, including the default login page and the UsernamePasswordAuthenticationFilter. To change this behavior and force Spring Boot to use the OAuth2 protocol for login, we need to replace the .loginForm() method with .oauth2Login().

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {

        httpSecurity.authorizeHttpRequests()
                .requestMatchers("/public").permitAll()
                .anyRequest().authenticated()
                .and()
                .oauth2Login();

       return  httpSecurity.build();
    }
}

5.4. OAuth Client Registrations

Spring Security will automatically create a ClientRegistrationRepository (by default InMemoryClientRegistrationRepository instance to store ClientRegistration objects in memory ) and register the client specified in the application.properties file (in our case, keycloak).

The ClientRegistrationRepository interface is part of Spring Security’s OAuth2 client support and it serves as a central repository for managing client registrations. It provides methods for retrieving the ClientRegistration object by their registration ID, getting a list of all registered clients, and adding or removing a client registration.

A ClientRegistration interface represents a client registration with an OAuth2/OIDC provider such as Keycloak, Github, Google etc. It contains information such as the client ID, client secret, redirect URI, authorization grant type, issuer URI, token URI, and other properties needed for authenticating and authorizing with the provider.

The .oauth2Login() method configures the application to use OAuth 2.0 for authentication. This method sets up the necessary configuration for the OAuth 2.0 login flow, including setting the authentication endpoint and callback URL. (It adds the OAuth2AuthorizationRequestRedirectFilter & OAuth2LoginAuthenticationFilter to the filter chain).

6. Test

Now let’s try to access one of the endpoints that we have in the EmployeeRestAPI /api/employees (protected endpoint), we will be redirected automatically to the login page of the keycloak server.

Provide the credentials of the user we just created (test-user/password), and you will be granted access to the endpoint and a successful response will be returned.

7. Authentication Flow

The following diagram depicts the process when a user requests a protected resource. Spring Security will redirect the user to Keycloak for authentication. After successful authentication, our backend will create a session for the user based on the information provided by Keycloak.

Here is the workflow of OAuth2 authentication using Spring Security and Keycloak, when a user sends a request to /api/employee:

  • The user sends a request to /api/employees.
  • Spring Security (OAuth2 Filter) intercepts the request and checks if the user is authenticated. If not, Spring Security redirects the user to the Keycloak login page.
  • The user enters their credentials on the Keycloak login page and submits the form.
  • Keycloak verifies the user’s credentials and generates an authorization code, which is sent to the redirect URI.
  • Spring Security requests Keycloak with the authorization code to get an access token.
  • Keycloak returns the access token to our Spring Boot app.
  • Spring Security requests the /user-info endpoint to get the user’s information.
  • The session is created.

8. Conclusion

Integrating Spring Boot Security with OAuth2 client and Keycloak can greatly enhance the security of an application. With Keycloak as the identity provider, we can centralize the management of users and access control policies, while Spring Security provides a flexible and customizable framework for securing the application’s resources.

Through the use of the OAuth2 protocol, we can enable seamless and secure authentication and authorization flows, while also allowing for fine-grained control over access to specific resources.

Happy Learning !!

Sourcecode on Github

Comments

Subscribe
Notify of
guest
13 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.