> Markdown version of [Vaadin Security Configurer](https://vaadin.com/docs/next/flow/security/vaadin-security-configurer). Section index: [llms.txt](https://vaadin.com/docs/next/flow/llms.txt)

### <a id="configurer"></a>VaadinSecurityConfigurer

#### <a id="overview"></a>Overview

`VaadinSecurityConfigurer` is a Spring Security HTTP configurer specifically designed for Vaadin applications. It provides built-in customizers to configure security settings for Flow and Hilla by integrating with Spring Security and specialized methods to handle view access control and default security workflows in Vaadin applications. This configurer follows Spring Security’s recommended patterns for security configuration and allows for modular, composable security customization.

#### <a id="usage"></a>Usage

The `VaadinSecurityConfigurer` can be used in a Spring Security configuration class to set up security for Vaadin applications:

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
            configurer.loginView(MyLoginView.class);
        }).build();
    }
}
```

#### <a id="applied-configurers"></a>Applied Configurers

The `VaadinSecurityConfigurer` applies several other Spring Security configurers to set up the security filter chain:

- `FormLoginConfigurer` — If a login view is set with `loginView(Class)` (or overloads)

- `OAuth2LoginConfigurer` — If a login page for OAuth2 authentication is set with `oauth2LoginPage(String)` (or overloads)

- `CsrfConfigurer` — To allow, internal framework requests (can be disabled)

- `LogoutConfigurer` — To configure logout handlers for Vaadin applications (can be disabled)

- `RequestCacheConfigurer` — To set a request cache designed for Vaadin applications (can be disabled)

- `ExceptionHandlingConfigurer` — To configure proper exception handling for Vaadin applications (can be disabled)

- `AuthorizeHttpRequestsConfigurer` — To permit internal framework requests and other public endpoints (can be disabled)

- `SessionManagementConfigurer` — To handle expired sessions in a way the Vaadin client understands (can be disabled)

#### <a id="shared-objects"></a>Shared Objects

The following beans are shared by this configurer (if not already shared):

- `RequestUtil` — Utility class for request-based security checks

- `AuthenticationContext` — Provides information about the current logged-in user and its roles

- `NavigationAccessControl` — Entry point for navigation access control

- `VaadinRolePrefixHolder` — Holds role prefix accessible outside an active request

- `VaadinDefaultRequestCache` — A request cache implementation which ignores requests that are not for routes

- `VaadinSavedRequestAwareAuthenticationSuccessHandler` — A strategy that uses an available VaadinSession for retrieving the security context

- `ClientRegistrationRepository` — The repository of the OAuth2 client registrations of the application

- `OidcUserService` — The service that loads the authenticated user, shared only when Keycloak role mapping is enabled with `keycloakRoleMapping()`

#### <a id="configuration-methods"></a>Configuration Methods

##### <a id="login-view-configuration"></a>Login View Configuration

```java
public VaadinSecurityConfigurer loginView(Class<? extends Component> loginView)
```

Configures the login view for use in a Flow application. The provided login view class must be annotated with `@Route`.

```java
public VaadinSecurityConfigurer loginView(Class<? extends Component> loginView, String logoutSuccessUrl)
```

Configures the login view for use in a Flow application and the logout success URL.

```java
public VaadinSecurityConfigurer loginView(String loginView)
```

Configures the login view for use in a Hilla application. This is used when your application uses a Hilla-based login view that is available at the given path.

```java
public VaadinSecurityConfigurer loginView(String loginView, String logoutSuccessUrl)
```

Configures the login view for use in a Hilla application and the logout success URL.

An unauthenticated request for a sub-resource of a protected path — a stylesheet, a script, an image, or a font — is answered with `401 Unauthorized` instead of being redirected to the login view. (since V25.3) A redirect can’t be rendered as the resource the browser asked for, and it ends in a redirect loop that reports the login view rather than the resource that was denied. Requests for a page keep the redirect. The two are told apart by the `Sec-Fetch-Dest` header the browser sends, and a request without that header counts as a page request.

##### <a id="oauth2-configuration"></a>OAuth2 Configuration

```java
public VaadinSecurityConfigurer oauth2LoginPage(String oauth2LoginPage)
```

Configures the login page for OAuth2 authentication. If using Spring’s OAuth2 client, this should be set to Spring’s internal redirect endpoint `/oauth2/authorization/{registrationId}` where `{registrationId}` is the ID of the OAuth2 client registration.

```java
public VaadinSecurityConfigurer oauth2LoginPage(String oauth2LoginPage, String postLogoutRedirectUri)
```

Configures the login page for OAuth2 authentication and the post-logout redirect URI.

```java
public VaadinSecurityConfigurer keycloakRoleMapping()
```

Enables mapping of Keycloak realm and client roles to Spring Security granted authorities (disabled by default). (V25.4 pre-release) Keycloak puts the roles of a user into the access token, so they aren’t part of the authenticated user by default. Enabling the mapping decodes the access token and maps its roles, which makes `@RolesAllowed("admin")` and `hasRole("admin")` match a Keycloak role named `admin`. Works only together with `oauth2LoginPage(String)` and its overloads. See [Keycloak Role Mapping](https://vaadin.com/docs/next/flow/integrations/spring/oauth2.md#keycloak-role-mapping) for details.

##### <a id="logout-configuration"></a>Logout Configuration

```java
public VaadinSecurityConfigurer logoutSuccessHandler(LogoutSuccessHandler logoutSuccessHandler)
```

Configures the handler for a successful logout. This overrides the default handler configured automatically with either `loginView(Class)` or `oauth2LoginPage(String)` (and their overloads).

```java
public VaadinSecurityConfigurer addLogoutHandler(LogoutHandler logoutHandler)
```

Adds a `LogoutHandler` to the list of logout handlers.

##### <a id="feature-toggles"></a>Feature Toggles

```java
public VaadinSecurityConfigurer enableCsrfConfiguration(boolean enableCsrfConfiguration)
```

Enables or disables automatic CSRF configuration (enabled by default). This configurer will automatically configure Spring’s CSRF filter to allow Vaadin internal framework requests to be properly processed.

```java
public VaadinSecurityConfigurer enableLogoutConfiguration(boolean enableLogoutConfiguration)
```

Enables or disables automatic logout configuration (enabled by default). This configurer will automatically configure logout behavior to work properly with Flow and Hilla.

```java
public VaadinSecurityConfigurer enableRequestCacheConfiguration(boolean enableRequestCacheConfiguration)
```

Enables or disables automatic configuration of the request cache (enabled by default). This configurer will automatically configure the request cache to work properly with Vaadin’s internal framework requests.

```java
public VaadinSecurityConfigurer enableExceptionHandlingConfiguration(boolean enableExceptionHandlingConfiguration)
```

Enables or disables automatic configuration of exception handling (enabled by default). This configurer will automatically configure exception handling to work properly with Flow and Hilla.

```java
public VaadinSecurityConfigurer enableAuthorizedRequestsConfiguration(boolean enableAuthorizedRequestsConfiguration)
```

Enables or disables automatic configuration of authorized requests (enabled by default). This configurer will automatically configure authorized requests to permit requests to anonymous Flow and Hilla views, and static assets.

```java
public VaadinSecurityConfigurer enableSessionManagementConfiguration(boolean enableSessionManagementConfiguration)
```

Enables or disables automatic configuration of session management (enabled by default). This configurer automatically configures a `VaadinExpiredSessionStrategy`, so that a session expired by Spring Security concurrency control is handled in a way the Vaadin client understands. The strategy is only used by Spring Security when concurrency control is active, that is, when the application sets a maximum number of sessions. It’s only configured if the application has session management configured, which `@EnableWebSecurity` does by default.

Note that the configured strategy replaces both a strategy and an expired URL set directly on `HttpSecurity`, since Spring Security uses the expired URL only when no strategy is set. Use `expiredSessionStrategy()` to configure a custom strategy, or disable this configuration.

```java
public VaadinSecurityConfigurer expiredSessionStrategy(SessionInformationExpiredStrategy expiredSessionStrategy)
```

Sets the strategy used when Spring Security concurrency control detects an expired session. Defaults to `VaadinExpiredSessionStrategy`. Pass `null` to fall back to the default strategy.

```java
public VaadinSecurityConfigurer enableNavigationAccessControl(boolean enableNavigationAccessControl)
```

Enables or disables configuration of `NavigationAccessControl`. `NavigationAccessControl` is enabled by default.

##### <a id="request-matchers"></a>Request Matchers

```java
public VaadinSecurityConfigurer anyRequest(Consumer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizedUrl> anyRequestAuthorizeRule)
```

Configures the access rule for any request not matching other configured rules. The default rule is to forbid the access, which is the equivalent of passing `AuthorizedUrl::denyAll()` to this method. This means that extra security rules (path matchers) are required for protected URLs not handled by the framework.

> **Note: Catch-all Rule and Custom Not-Found Pages**
>
> Because the default rule denies access, any request that doesn’t match a Vaadin route — including a request for a non-existing page — is blocked at the HTTP layer before it reaches the Vaadin servlet. As a result, a custom `RouteNotFoundError` view isn’t rendered for such requests; unauthenticated users are redirected to the login page (or receive an error) instead.
>
> To show a custom not-found page, relax this rule so that unmatched requests can reach the Vaadin servlet — for example, by permitting them:
>
> ```java
> http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
>     configurer.loginView(LoginView.class)
>             .anyRequest(AuthorizedUrl::permitAll);
> });
> ```
>
> Alternatively, pass `null` to `anyRequest()` to disable the automatic catch-all rule and configure the access rules for unmatched requests yourself with Spring Security.
>
> Relaxing the catch-all rule doesn’t expose protected views: real routes are still guarded by the secured-route request matchers at the HTTP layer and by navigation access control at the navigation level. The custom error view itself still needs an appropriate security annotation (such as `@AnonymousAllowed`) to be rendered. See [Router Exception Handling](https://vaadin.com/docs/next/flow/routing/exceptions.md) for details on annotating custom error views.

```java
public RequestMatcher defaultPermitMatcher()
```

Creates and returns a composite `RequestMatcher` for identifying requests that should be permitted without authentication within a Vaadin application. This matcher combines multiple specific matchers, including those for framework internal requests, anonymous browser-callable services, allowed Hilla views, anonymous routes, custom web icons, and default security configurations.

#### <a id="examples"></a>Examples

##### <a id="basic-configuration"></a>Basic Configuration

`VaadinSecurityConfigurer` exposes a factory method `vaadin` that creates a new instance of the `VaadinSecurityConfigurer`:

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
            configurer.loginView(LoginView.class);
        }).build();
    }
}
```

##### <a id="multiple-filter-chains"></a>Multiple Filter Chains

To configure multiple filter chains, use `@Order` annotation to specify the order of the filter chains. The lower the order value, the higher the priority of the filter chain.

`VaadinSecurityConfigurer` should be used at most in one filter chain. Using it in multiple chains may behave in an unexpected ways, e.g. login view being overwritten in `NavigationAccessControl`.

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Order(1)
    @Bean
    SecurityFilterChain privateFilterChain(HttpSecurity http) throws Exception {
        return http.securityMatcher("/private/**")
                .with(VaadinSecurityConfigurer.vaadin(), configurer -> {
                    configurer.loginView(LoginView.class);
                }).build();
    }

    @Order(0)
    @Bean
    SecurityFilterChain publicFilterChain(HttpSecurity http) throws Exception {
        return http.securityMatcher("/public/**")
                .authorizeHttpRequests(auth -> {
                    auth.anyRequest(AuthorizedUrl::permitAll);
                }).build();
    }
}
```

Example of two separate security filters: one for handling stateless Spring Boot APIs with token-based authentication, and another for a stateful Vaadin web application with login view.

```java
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfigurationAPI {

    private final UserDetailsService userDetailsService;
    private final AuthTokenFilter authTokenFilter;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    @Bean
    @Order(0)
    public SecurityFilterChain securityFilterApi(HttpSecurity http) throws Exception {
        HttpSecurity httpSecurity = http
                .securityMatcher("/api/**")
                .sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/api/v1/login").anonymous()
                        .requestMatchers("/api/v1/admin/**").hasRole("ADMIN")
                        .requestMatchers("/api/v1/**").authenticated());

        http.authenticationProvider(authenticationProvider());
        http.addFilterBefore(authTokenFilter, UsernamePasswordAuthenticationFilter.class);

        return httpSecurity.build();
    }
}

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Order(1)
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
            configurer.loginView(LoginView.class);
        }).build();
    }
}
```

##### <a id="custom-authorization-rules"></a>Custom Authorization Rules

In Spring Security, **Custom Authorization Rules** are developer-defined rules that control who can access certain HTTP routes or resources. In Vaadin, they complement the access control already applied to views through annotations like `@PermitAll` or `@RolesAllowed`.

###### <a id="use-cases"></a>Use Cases

- Protect REST endpoints that are not part of Vaadin navigation.

- Define public routes that don’t require authentication (`/public/**`).

- Restrict specific areas based on roles (`/admin-only/**`).

- Allow access to error pages without authentication (`/error`).

###### <a id="how-it-works-with-vaadin"></a>How It Works With Vaadin

Vaadin uses annotations to control access to views at the navigation level, while Spring Security applies these **Custom Authorization Rules** at the HTTP request level. Both layers work together to ensure a secure application.

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth
                .requestMatchers("/admin-only/**").hasAnyRole("ADMIN")
                .requestMatchers("/public/**").permitAll()
                .requestMatchers("/error").permitAll());

        http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
            configurer.loginView(LoginView.class)
                    .logoutSuccessHandler(this::onLogoutOnNonVaadinUrl)
                    .addLogoutHandler((request, response, authentication) -> {
                        // Custom logout logic
                    });
        });

        return http.build();
    }
}
```

##### <a id="handling-expired-sessions"></a>Handling Expired Sessions

When an application limits each user to one active session with Spring Security’s concurrency control, logging in on a second device must invalidate the session on the first device. Configure the maximum number of sessions on `sessionManagement()`, and `VaadinSecurityConfigurer` automatically makes sure the browser with the invalidated session shows Vaadin’s session-expired dialog and reloads, instead of getting a plain-text page it can’t use:

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http.with(VaadinSecurityConfigurer.vaadin(),
                        configurer -> configurer.loginView(LoginView.class))
                .sessionManagement(sessionManagement -> sessionManagement
                        .sessionConcurrency(concurrency -> concurrency
                                .maximumSessions(1)))
                .build();
    }
}
```

Applications that don’t configure a maximum number of sessions aren’t affected, because Spring Security only checks for expired sessions when concurrency control is active.

To handle the expiration differently, for example to send the user to a custom page, pass a custom strategy with `expiredSessionStrategy()`:

```java
http.with(VaadinSecurityConfigurer.vaadin(), configurer -> configurer
        .expiredSessionStrategy(event -> event.getResponse()
                .sendRedirect("/session-expired")));
```

##### <a id="disabling-features"></a>Disabling Features

The `VaadinSecurityConfigurer` provides some security features enabled by default to ensure smooth integration between Vaadin and Spring Security. In certain scenarios, you may disable these defaults to apply your own custom security configuration.

###### <a id="features-that-can-be-disabled"></a>Features That Can Be Disabled

- **CSRF Configuration** (`enableCsrfConfiguration(false)`): By default, the configurer automatically sets up Spring Security’s CSRF filter so that Vaadin internal framework requests (such as UIDL, heartbeat, and push) are processed without issues. Disabling this means you will need to handle CSRF configuration yourself, ensuring that internal Vaadin requests are not blocked.

- **Navigation Access Control** (`enableNavigationAccessControl(false)`): Vaadin enables `NavigationAccessControl` by default to check access annotations (such as `@PermitAll` or `@RolesAllowed`) when navigating between views. Disabling this means Vaadin will no longer enforce annotation-based navigation security, and you will need to implement your own access control logic for view navigation.

- **Session Management Configuration** (`enableSessionManagementConfiguration(false)`): By default, the configurer installs `VaadinExpiredSessionStrategy` so that a session expired by Spring Security concurrency control is handled in a way the Vaadin client understands. Disabling this restores Spring Security’s default expired-session response, which the Vaadin client can’t process.

###### <a id="when-to-disable"></a>When To Disable

You should only disable these features if:

- You have a clear, secure, and tested replacement for the default behavior.

- You understand the implications of removing these protections.

- Your application has special requirements that conflict with the defaults.

In most applications, keeping these features enabled is the recommended and safest option.

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
            configurer.loginView(LoginView.class)
                    .enableCsrfConfiguration(false)
                    .enableNavigationAccessControl(false);
        }).build();
    }
}
```

`164DDBB1-3DC0-4E30-B8B9-D280BB83341F`
