A Quick Guide to Using Keycloak with Spring Boot

1. Overview

In this article, we’ll cover the basics of setting up a Keycloak server, how to connect a Spring Boot application to it, and how to use it with Spring Security.

2. What Is Keycloak?

Keycloak is an open source Identity and Access Management solution targeted towards modern applications and services.

Keycloak offers features such as Single-Sign-On (SSO), Identity Brokering and Social Login, User Federation, Client Adapters, an Admin Console, and an Account Management Console. To learn more about Keycloak, please visit the official page.

In our tutorial, we’ll be using the Admin Console of Keycloak for setting up and then connecting to Spring Boot using the Keycloak Client Adapter.

3. Setting Up a Keycloak Server


==== 3.1. Downloading and Installing Keycloak

There’re several distributions to choose from.

However, in this tutorial, we’ll be using the standalone version.

Download Keycloak-3.3.0.Final Standalone server distribution from the official source.

Once we’ve downloaded the Standalone server distribution, we can unzip and start Keycloak from the terminal:

unzip keycloak-3.3.0.Final.zip
cd keycloak-3.3.0.Final/bin
./standalone.sh -Djboss.socket.binding.port-offset=100

After running ./standalone.sh, Keycloak will be starting its services. Once we see a line containing Keycloak 3.3.0.Final (WildFly Core 3.0.1.Final) started, we’ll know its start-up is complete.

Open a browser and visit http://localhost:8180. We’ll be redirected to http://localhost:8180/auth to create an administrative login:

image

Let’s create a user named “initial1” with the password “zaq1!QAZ“.

We now see “Welcome to Keycloak”:

image

We can now proceed to the Administrative Console.

3.2. Creating a Realm

Let’s navigate our mouse into the upper left upper corner to discover the “Create a Realm” button:

image

We’re naming it “SpringBootKeycloak“:

image

3.3. Creating a Client

Now we’ll navigate to the Clients page. As we can see in the image below, Keycloak comes with Clients that are already built in:

image

But we need to add a client to our application, so we click “Create”. We’ll call the new Client “login-app:

image

In the next screen, for this tutorial, we’ll be leaving all the defaults except the “Valid Redirect URIs field”. We’ll be redirected to the port 8081:

image

3.4. Creating a Role and a User

Keycloak uses the Role-Based Access. Therefore, each user must have a role.

We need to navigate to the “Role” page:

image

Then, we add the “user” role:

image

Now we’ve got a role that can be assigned to users, but there are no users yet. So let’s go the “Users” page and add one:

image

We add the user “user1”:

image

Once the user is created, we’ll be shown this page:

image

We can now go to the “Credentials” tab. We’ll be setting the password to “[email protected]”:

image

We navigate to the “Role Mappings” tab. We’ll be assigning the user role:

image

3.5. Creating a Custom Login Page

Keycloak provides a REST API for generating and refreshing access tokens. We can easily use this API to create our own login page.

First, we need to acquire an access token from Keycloak by sending a POST request to this URL:

http://localhost:8180/auth/realms/master/protocol/openid-connect/token

The request should have this JSON body:

{
    'client_id': 'your_client_id',
    'username': 'your_username',
    'password': 'your_password',
    'grant_type': 'password'
}

In response, we’ll get an access_token and a refresh_token.

The access token should be used in every request to a Keycloak-protected resource by simply placing it in the Authorization header:

headers: {
    'Authorization': 'Bearer' + access_token
}

Once the access token has expired, we can refresh it by sending a POST request to the same URL as above, but containing the refresh token instead of username and password:

{
    'client_id': 'your_client_id',
    'refresh_token': refresh_token_from_previous_request,
    'grant_type': 'refresh_token'
}

This will respond with a new access_token and refresh_token.

4. Creating a Spring Boot Application


==== 4.1. Dependencies

The latest Spring Boot Keycloak Starter dependencies can be found on Maven Central.

The Keycloak Spring Boot adapter capitalizes on Spring Boot’s auto-configuration, so all we need to do is add the Keycloak Spring Boot starter to our project.

Within the dependencies XML element, we need the following to run Keycloak with Spring Boot:

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-spring-boot-starter</artifactId>
</dependency>

After the dependencies XML element, we need to specify dependencyManagement for Keycloak:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.keycloak.bom</groupId>
            <artifactId>keycloak-adapter-bom</artifactId>
            <version>3.3.0.Final</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

The following embedded containers are supported now and don’t require any extra dependencies if using Spring Boot Keycloak Starter:

  • Tomcat

  • Undertow

  • Jetty

4.2. Thymeleaf Web Pages

We’re using Thymeleaf for our web pages.

We’ve got three pages:

  • external.html – an externally facing web page for the public

  • customers.html – an internally facing page that will have its access restricted to only authenticated users with the role “user.”

  • layout.html – a simple layout, consisting of two fragments, that is used for both the externally facing page and the internally facing page

The code for the Thymeleaf templates is available on Github.

4.3. Controller

The web controller maps the internal and external URLs to the appropriate Thymeleaf templates:

@GetMapping(path = "/")
public String index() {
    return "external";
}

@GetMapping(path = "/customers")
public String customers(Model model) {
    addCustomers();
    model.addAttribute("customers", customerDAO.findAll());
    return "customers";
}

For the path /customers, we’re retrieving all customers from a repository and adding the result as an attribute to Model. Later on, we iterate through the results in Thymeleaf.

4.4. Keycloak Configuration

Here’s the basic, mandatory configuration:

keycloak.auth-server-url=http://localhost:8180/auth
keycloak.realm=SpringBootKeycloak
keycloak.resource=login-app
keycloak.public-client=true

As we recall, we started Keycloak on port 8180, hence the path specified in keycloak.auth-server-url. We enter the realm name we created in the Keycloak admin console.

The value we specify in keycloak.resource matches the client we named in the admin console.

Here are security constraints we’ll be using:

keycloak.security-constraints[0].authRoles[0]=user
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/customers/*

The above security restraints state ensure every request to /customers/* will only be authorized if the one requesting it’s an authenticated user with the role “user”.

4.5. Demonstration

Now, we’re ready to test our application. To run a Spring Boot application, we can start it easily through an IDE like Spring Tool Suite (STS) or run this command in the terminal:

mvn clean spring-boot:run

We visit localhost:8081:

image

Now we click “customers” to enter the intranet, which is the location of sensitive information.

We can see that we’ve been redirected to authenticate through Keycloak to see if we’re authorized to view this content:

image

Once we authenticate and our authorization is checked by Keycloak, we’re redirected to the restricted customers’ page:

image

Now we’ve finished the set up of connecting Spring Boot with Keycloak and demonstrating how it works.

Now we’ll be reviewing how to use Spring Security in conjunction with our existing application.

5. Spring Security

There is a Keycloak Spring Security Adapter, and it’s already included in our Spring Boot Keycloak Starter dependency. We’ll now see how to integrate Spring Security with Keycloak.

5.1. Dependency

To use Spring Security with Spring Boot, we must add this dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>1.5.3</version>
</dependency>

The latest Spring Boot Starter Security release can be found on Maven Central.

5.2. Configuration Class

Keycloak provides a KeycloakWebSecurityConfigurerAdapter as a convenient base class for creating a WebSecurityConfigurer instance, which is convenient because a configuration class extending WebSecurityConfigurerAdapter is needed for any application secured by Spring Security:

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(
      AuthenticationManagerBuilder auth) throws Exception {

        KeycloakAuthenticationProvider keycloakAuthenticationProvider
         = keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
          new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Bean
    public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(
          new SessionRegistryImpl());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.authorizeRequests()
          .antMatchers("/customers*")
          .hasRole("user")
          .anyRequest()
          .permitAll();
    }
}

Please note the code above:

  • configureGlobal: tasks the SimpleAuthorityMapper to make sure roles are not prefixed with ROLE_

  • keycloakConfigResolver: this defines that we want to use the Spring Boot properties file support instead of the default keycloak.json

5.3. application.properties

Because we’ve set up the security constraints with Spring Security, we can remove the previous security constraints we placed in application.properties.

Now we’ll add this to our application.properties:

keycloak.principal-attribute=preferred_username

5.4. Controller

To make use of a user’s username, we’re updating our controller to inject the Principal:

@GetMapping(path = "/customers")
public String customers(Principal principal, Model model){
    addCustomers();
    model.addAttribute("customers", customerDAO.findAll());
    model.addAttribute("username", principal.getName());
    return "customers";
}

5.5. Thymeleaf

Under the div container, we’ll add this one line to greet the user:

<h1>Hello, <span th:text="${username}">--name--</span>.</h1>

5.6. Demo

Now, after we authenticate and are taken to the internal customers’ page, we’ll see:

image

6 Conclusion

In this tutorial, we’ve configured a Keycloak server and used it with a Spring Boot Application.

We’ve also seen how to set up Spring Security and use it in conjunction with Keycloak. A working version of the code shown in this article is available over on Github.

Leave a Reply

Your email address will not be published.