Friends of OpenJDK Today

Vaadin, OAuth2, and Keycloak

January 24, 2023

Author(s)

  • Simon Martinelli

    Simon Martinelli is a Java Champion, a Vaadin Champion, and an Oracle ACE Pro. He regularly shares his knowledge in articles, speaks at international conferences, and writes his blog: https://martinelli.ch. ... Learn more

This article shows how to configure Vaadin and Spring Security to use OAuth2 with Keycloak.

Keycloak

First, we must start Keycloak and configure a realm. The easiest way is to start Keycloak with Docker.
Caution: This is just for development purposes. Don't use the setup in production.

docker run -d -p 8180:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin \ 
       quay.io/keycloak/keycloak:20.0.1 start-dev

Now you can log in to the admin console: http://localhost:8180/admin (user: admin, password: admin)

Next we must create a realm and a user, add roles to the user, and finally, a client.

Create a realm

  1. Click on the drop-down in the upper left corner and select "Create realm"
  2. Enter the realm name "vaadin" and save

Create realm roles

  1. Select "Realm roles" in the menu
  2. Click "Create role"
  3. Enter the role name "admin" and save
  4. Repeat steps 1 to 3 with the role "user"

Create users

  1. Select "Users" in the menu
  2. Click on "Create new user"
  3. Enter the user name "admin"
  4. Click on "Create"
  5. Select the tab "Credentials" and set a password
  6. Disable "Temporary" to prevent having to update the password on the first login
  7. Click "Save"
  8. Select the tab "Role mapping"
  9. Click on "Assign role"
  10. Choose the previously created roles "admin" and "user"
  11. Do the same for the user with username "user" but add only the role "user"

Create a client

  1. Select "Client" in the menu
  2. Click on "Create client"
  3. Enter the client id "vaadin"
  4. Click next and the save
  5. In the "Access settings" set
    • "Valid redirect URIs" to http://localhost:8080/*
    • "Web origins" to http://localhost:8080

Important: Role Mapping

Now comes a crucial step. We must disable the role mapping to the ID token. When I created the example, the roles were missing in the application, but I found the solution thanks to Thomas Vitale's answer on StackOverflow.

  1. Select "Client scopes"
  2. Select the client scope "roles"
  3. Click on the tab "Mappers"
  4. Select "realm roles"
  5. Disable "Add to ID token"

The configuration must look like this:

Vaadin Application with Security Configuration

First, we need to extend VaadinWebSecurity to set up the Vaadin Spring security integration. There we override the configure method.

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().requestMatchers(new AntPathRequestMatcher("/images/*.png")).permitAll();

    http.oauth2Login()
            .and()
            .logout()
            .addLogoutHandler(keycloakLogoutHandler)
            .logoutSuccessUrl("/");

    super.configure(http);
}

Starting from line 5, the generic OAuth2 login is configured, and a special LogoutHandler for Keycloak is configured. The LogoutHandler uses the Keycloak REST API to log out.

As we configured to map the roles to the userinfo we now need to map these roles to GrantedAuthority. The roles will be in the claim "realm_access".

@Bean
public GrantedAuthoritiesMapper userAuthoritiesMapperForKeycloak() {
    return authorities -> {
        Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
        var authority = authorities.iterator().next();

        if (authority instanceof OidcUserAuthority oidcUserAuthority) {
            var userInfo = oidcUserAuthority.getUserInfo();

            if (userInfo.hasClaim("realm_access")) {
                var realmAccess = userInfo.getClaimAsMap("realm_access");
                var roles = (Collection<String>) realmAccess.get("roles");
                mappedAuthorities.addAll(roles.stream()
                        .map(role -> new SimpleGrantedAuthority("ROLE_" + role.toUpperCase()))
                        .toList());
            }
        }
        return mappedAuthorities;
    };
}

Finally, we must add the OAuth2 configuration in the application.properties file:

spring.security.oauth2.client.registration.keycloak.client-id=vaadin
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.scope=openid
spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8180/realms/vaadin
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username

Now you can start the application and open http://localhost:8080.

As you can see in the menu on the left, there is only one entry, "Index".

Click on the "Sign in" button in the lower left corner. This will direct you to the Keycloak login screen.

Sign in with admin/admin, and you'll be redirected to the app:

Now you have access to all views.

Conclusion

Setting up Vaadin, Spring Security, and Keycloak is straight forwarded. The only tricky part was the role mapping to get the realm roles as GranteAuthority.

Topics:

Related Articles

View All

Author(s)

  • Simon Martinelli

    Simon Martinelli is a Java Champion, a Vaadin Champion, and an Oracle ACE Pro. He regularly shares his knowledge in articles, speaks at international conferences, and writes his blog: https://martinelli.ch. ... Learn more

Comments (0)

Your email address will not be published. Required fields are marked *

Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.

Save my name, email, and website in this browser for the next time I comment.

Subscribe to foojay updates:

https://foojay.io/feed/
Copied to the clipboard