Many companies use Microsoft 365, so letting users log in with their Microsoft account is a good choice. This blog post shows how to secure your Vaadin applications using Microsoft Entra for authentication and authorization and explains how Karibu Testing must be configured.
Step 1: Create an Application in Entra
The first step is to create an application, configure roles, assign users, and set the redirect URI.
To create an application, log in to http://entra.microsoft.com and select “Applications” -> “Enterprise applications.” There, you can create a new application. Select “Register an application to integrate with Microsoft Entra ID (App you’re developing).”
Set a name and add a Redirect URI like in the screenshot. Choose Web and set http://localhost:8080/login/oauth2/code/
as the URI. As you can see, this URI is application-environment-specific, and you will need to create an app registration per stage (dev, test, production, etc.).
Create App Role
We want to use role-based security in our application. To create an app role, go to “App registrations” and select the application. Click on “App roles”:
And create the app role. In this case, we will create an Administrator account. The value will be what you will get in the JWT token. I prefer to have the role names in uppercase.
Assign Users
Once you’ve created your application role, return to “Enterprise applications” and click “Users and groups.” You can assign existing users or groups to the application roles:
Create Client Secret
To be able to connect to Entra from the application, we must create a client secret that allows our application to connect to Entra:
Make sure to copy the value of the client secret; we’ll need that in the application configuration.
We also need to copy the ClientId and the TenantId. The ClientId (Application (client) ID) can be found on the App registration overview page (below), and the TenantId is located on the Entra overview page.
Step 2: Configure OAuth2 with Entra in our Application
As we have a Vaadin application, we will use the OAuth 2.0 authorization code grant flow.
Add Dependencies
First, add the Microsoft starter dependencies and the OAuth2 client starter. Don’t be confused about the dependency’s name. Entra is the new name for Azure Active Directory (Azure AD).
<dependency> <groupId>com.azure.spring</groupId> <artifactId>spring-cloud-azure-starter-active-directory</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency>
Configure the Application
There are four properties to set. For simplicity, the snippet below shows them as Java properties. But you must be careful with secret values.
Please don’t put them into application.properties or commit them to your Git repository because they are secret values you don’t want to share with the public.
It’s better to set the properties on the platform where your application is running, for example, as environment variables.
spring.cloud.azure.active-directory.enabled=true spring.cloud.azure.active-directory.profile.tenant-id=<teanantId> spring.cloud.azure.active-directory.credential.client-id=<clientId> spring.cloud.azure.active-directory.credential.client-secret=<clientSecret>
Enable Entra Security
To integrate Entra with Spring Security, we need to adjust the security configuration. We extend from VaadinWebSecurity because we have a Vaadin application.
Add AadWebApplicationHttpSecurityConfigurer.aadWebApplication()
to enable Entra security as the first line in the configure method
.
Also, ensure you don’t set a LoginView because the login will happen with the Microsoft login.
@EnableWebSecurity @Configuration public class SecurityConfiguration extends VaadinWebSecurity { @Override protected void configure(HttpSecurity http) throws Exception { http.with(AadWebApplicationHttpSecurityConfigurer.aadWebApplication(), c -> { }); http.authorizeHttpRequests(authorize -> authorize .requestMatchers(new AntPathRequestMatcher("/images/*.png"), new AntPathRequestMatcher("/line-awesome/**/*.svg"), EndpointRequest.to(HealthEndpoint.class)) .permitAll()); super.configure(http); } }
Configure Role Prefix
The security configuration will prefix the roles with APPROLE_. To use the role name that we set in Microsoft Entra, we must configure the default prefix because ROLE_ is the prefix by default.
@Configuration public class RolePrefixConfiguration { @Bean public GrantedAuthorityDefaults grantedAuthorityDefaults() { return new GrantedAuthorityDefaults("APPROLE_"); } }
Roles in Action
The setup is completed, and we can use role-based security in the Vaadin application.
It’s convenient to define the roles as constants, like in the example, in case the role name changes, so you only have to change it in one place.
@RolesAllowed({ Roles.USER, Roles.ADMIN }) @Route("event-registrations") public class EventRegistrationView extends Div implements HasUrlParameter<Long>, HasDynamicTitle {
Step 3: Setup Karibu Testing
To use Browserless Testing of Vaadin Applications with Karibu Testing, we must fake the Entra setup’s security context.
The most important part is the createOAuth2AuthenticationToken
Method.
An OAuth2AuthenticationToken
is created and then set to the SecurityContext
and the Karibu FakeRequest. The OidcIdToken
is created with minimal attributes that our application uses.
It’s also important to override the getUserPrincipal
method because no login is happening. Using OAuth2 means that the application assumes that a JWT is part of the request instead.
@SpringBootTest public abstract class KaribuTest { private static Routes routes; @Autowired protected ApplicationContext ctx; // Default user and role private String username = "john.doe@test.com"; private String name = "John Doe"; private String role = Roles.ADMIN; private OAuth2AuthenticationToken oAuth2AuthenticationToken; @BeforeAll public static void discoverRoutes() { Locale.setDefault(Locale.GERMAN); routes = new Routes().autoDiscoverViews("ch.martinelli.oss.registration.ui.views"); } @BeforeEach public void setup() { MockVaadin.INSTANCE.setMockRequestFactory(session -> new FakeRequest(session) { @Override public Principal getUserPrincipal() { createAuthentication(); return SecurityContextHolder.getContext().getAuthentication(); } }); final Function0<UI> uiFactory = UI::new; MockVaadin.setup(uiFactory, new MockSpringServlet(routes, ctx, uiFactory)); } @AfterEach public void tearDown() { logout(); MockVaadin.tearDown(); } protected void login(String username, String role) { this.username = username; this.role = role; oAuth2AuthenticationToken = null; createOAuth2AuthenticationToken(); } private void createAuthentication() { createOAuth2AuthenticationToken(); SecurityContextHolder.getContext().setAuthentication(oAuth2AuthenticationToken); FakeRequest request = (FakeRequest) VaadinServletRequest.getCurrent().getRequest(); request.setUserPrincipalInt(oAuth2AuthenticationToken); request.setUserInRole((principal, roleName) -> oAuth2AuthenticationToken.getPrincipal() .getAuthorities() .stream() .anyMatch(a -> a.getAuthority().equals(roleName))); } private void createOAuth2AuthenticationToken() { if (oAuth2AuthenticationToken == null) { OidcIdToken oidcIdToken = new OidcIdToken("tokenValue", null, null, Map.of("sub", "-", "preferred_username", username, "name", name)); DefaultOidcUser defaultOidcUser = new DefaultOidcUser(List.of(new SimpleGrantedAuthority(role)), oidcIdToken); oAuth2AuthenticationToken = new OAuth2AuthenticationToken(defaultOidcUser, defaultOidcUser.getAuthorities(), "oidc"); } } protected void logout() { try { SecurityContextHolder.getContext().setAuthentication(null); if (VaadinServletRequest.getCurrent() != null) { FakeRequest request = (FakeRequest) VaadinServletRequest.getCurrent().getRequest(); request.setUserPrincipalInt(null); request.setUserInRole((principal, roleName) -> false); } } catch (IllegalStateException e) { // Ignored } } }
Summary
Thanks to the spring-cloud-azure-starter-active-directory, the setup is straightforward. The Karibu Testing setup was more difficult, but thanks to Martin Mysny’s help, I was able to make it work.
To learn more, check out the official documentation: Spring Boot Starter for Microsoft Entra developer’s guide.