Docs

OAuth2 Authentication

Vaadin and Spring Security configuration for OAuth2 Authentication.

Vaadin applications can be configured to authenticate users using an existing account at an OAuth 2.0 Provider (e.g., GitHub) or at an OpenID Connect 1.0 Provider (e.g., Google).

This page focuses on how to configure a Spring Boot project to integrate OAuth2 authentication in Vaadin. It assumes you’re familiar with setting up Spring Security with Vaadin. For detailed information about Spring Security and OAuth2, consult the Spring documentation.

Application Configuration

To start, add the spring-security-oauth2-client dependency to your project. When using Spring Boot, use the following starter:

Source code
Maven
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
Gradle

Next, add the OAuth2 provider settings to the application’s configuration file. The following example configuration integrates a Keycloak OAuth2 provider. To setup a test environment, refer to the Keycloak Integration in Vaadin SSO Kit documentation.

Source code
application.properties
spring.security.oauth2.client.registration.keycloak.provider=keycloak
spring.security.oauth2.client.registration.keycloak.client-id=my-client-id
spring.security.oauth2.client.registration.keycloak.client-secret=<<client secret>>
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.scope=openid,profile

spring.security.oauth2.client.provider.keycloak.issuer-uri=http://keyclok.local:8180/realms/my-app
application.yaml

For integration with other OAuth2 providers, refer to the Spring Security documentation.

Enable OAuth2 Login in Vaadin

To enable OAuth2 login in a Vaadin application, use the VaadinSecurityConfigurer class and configure the login page and post-logout redirect URI using the oauth2LoginPage method.

Besides the HttpSecurity instance, there are two method parameters:

  • Login Page: The URI capable of initiating the authentication request. Usually, it’s /oauth2/authorization/{registrationId}, where registrationId refers to the client registered in the application configuration file.

  • Post Logout Redirect URI: The location where the user is redirected after logout.

The post logout redirect URI can be expressed as a relative or absolute URI, or as a template. The supported URI template variables are {baseScheme}, {baseHost}, {basePort}, {basePath}, and {baseUrl} — which is the same as {baseScheme}://{baseHost}{basePort}{basePath}.

Source code
Enable OAuth Login in VaadinSecurityConfigurer
@Configuration
class SecurityConfiguration {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
            configurer.oauth2LoginPage(
                        "/oauth2/authorization/keycloak", 1
                        "{baseUrl}/session-ended"         2
            );
        });
        return http.build();
    }
}
Enable OAuth Login in VaadinSecurityConfigurer
  1. Login page for initiating OAuth2 login with the Keycloak client.

  2. Post logout redirect URI uses a template to resolve dynamically the URL.

The oauth2LoginPage(String) method is a shortcut that defaults the post-logout redirect URL to {baseUrl}.

Keycloak Role Mapping

Keycloak puts the roles of a user into the access token rather than into the ID token, and it does so in the realm_access and resource_access claims, which aren’t part of the OpenID Connect specification. Spring Security maps neither of them, so @RolesAllowed("admin") and hasRole("admin") don’t match a Keycloak role named admin, and every user is rejected.

Mapping those roles is opt-in per security filter chain. Enable it by calling the keycloakRoleMapping() method of VaadinSecurityConfigurer:

Source code
Enable Keycloak Role Mapping
@Configuration
class SecurityConfiguration {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
            configurer.oauth2LoginPage("/oauth2/authorization/keycloak")
                    .keycloakRoleMapping(); 1
        });
        return http.build();
    }
}
Enable Keycloak Role Mapping
  1. Decodes the access token of the authenticated user and maps its roles to granted authorities.

Views and services can then be guarded with the plain Keycloak role name:

Source code
Java
@Route("admin")
@RolesAllowed("admin") // Matches the Keycloak realm role "admin"
public class AdminView extends VerticalLayout {
}

The mapping grants the following authorities:

  • The realm roles from the realm_access claim of the access token.

  • The roles that the resource_access claim grants for the client ID of the current client registration. Roles that it grants for other clients are ignored.

  • The scopes of the access token, prefixed with SCOPE_, as the default user service grants them.

  • The OidcUserAuthority of the authenticated user, built from the ID token and the userinfo claims, as the default user service grants it.

Realm roles and client roles both become role authorities that use the role prefix of the application, which is ROLE_ unless a GrantedAuthorityDefaults bean defines another prefix.

Note

The keycloakRoleMapping() method works only together with oauth2LoginPage() and its overloads. Without a login page for OAuth2 authentication, it logs a warning and has no effect.

Verifying the access token requires the JSON Web Key Set (JWKS) of the provider, which a client registration either resolves from its issuer-uri or takes from an explicitly configured jwk-set-uri. If the registration has no JWKS URI, or if the access token isn’t a JWT that the application can decode, the login still succeeds, but the user is mapped without any roles. Both cases are logged at debug level.

When the mapping is enabled, the configurer builds an OidcUserService for the OAuth2 login and shares it with the HttpSecurity instance, so it can be retrieved with http.getSharedObject(OidcUserService.class).

Mapping Roles on a Custom User Service

Enabling the mapping replaces the OidcUserService of the filter chain. An application that builds its own user service should therefore leave keycloakRoleMapping() off and install the KeycloakOidcUserMapper converter on that service instead:

Source code
Java
var oidcUserService = new OidcUserService();
oidcUserService.setOidcUserConverter(new KeycloakOidcUserMapper());

The mapper prefixes roles with ROLE_. To apply another prefix — for example, to match a GrantedAuthorityDefaults bean — pass it to the constructor:

Source code
Java
new KeycloakOidcUserMapper("AUTHORITY_");

Configure the resulting user service on the OAuth2 login as described in the Spring Security documentation.

EF8F6AC3-BE67-4BE2-9A78-C371C1D4B9FD

Updated