OnDemand
(Nico M)
September 19, 2025, 6:16am
1
Since 24.9 VaadinWebSecurity is deprecated and will be replaces in 24.9.
Do we need to switch to FilterChain? Does it then support stateless login? Looks like it needs deep changes
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
//ToDo
}
marcoc_753
(Marco Collovati)
September 19, 2025, 6:42am
2
VaadinWebSecurity will be removed in Vaadin 25.
The migration should not be so difficult; the new VaadinSecurityConfigurer provides basically the same feature that you can activate with VaadinWebSecurity but it is also more flexible.
Hereβs a simple example
Before
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends VaadinWebSecurity {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(registry -> {
registry.requestMatchers("/assets/**").permitAll();
});
super.configure(http);
setLoginView(http, "/login", "/");
}
}
After
@Configuration
@EnableWebSecurity
@Import(VaadinAwareSecurityContextHolderStrategyConfiguration.class)
public class SecurityConfig {
@Bean
public SecurityFilterChain vaadinSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(registry -> {
registry.requestMatchers("/assets/**").permitAll();
});
http.with(vaadin(), vaadin -> vaadin.loginView("/login", "/"));
return http.build()
}
}
For stateless login, you need to use VaadinStatelessSecurityConfigurer (that is already used under the hood by VaadinWebSecurity)
Before
@Override
protected void configure(HttpSecurity web) throws Exception {
...
setStatelessAuthentication(http,
new SecretKeySpec(Base64.getDecoder().decode(authSecret),
JwsAlgorithms.HS256),
"com.example.application");
...
}
After
@Bean
public SecurityFilterChain vaadinSecurityFilterChain(HttpSecurity http) throws Exception {
...
http.with(new VaadinStatelessSecurityConfigurer<>(),
stateless -> stateless.issuer("com.example.application")
.withSecretKey()
.secretKey(
new SecretKeySpec(
Base64.getDecoder().decode(authSecret),
JwsAlgorithms.HS256)
)
)
...
}
OnDemand
(Nico M)
September 19, 2025, 6:44am
3
Marco Collovati:
VaadinSecurityConfigurer
Ah okay Thank you, that information i was missing :)
Adam.87
(Adam Brusselback)
September 19, 2025, 2:31pm
4
Just for reference for others, I just upgraded my app and here is the complete before / after.
Before:
package ai.goacquire.frontend.config;
import ai.goacquire.frontend.security.CustomAuthenticationFailureHandler;
import ai.goacquire.frontend.security.CustomUserAuthoritiesMapper;
import ai.goacquire.frontend.security.OAuth2LoginSuccessHandler;
import com.vaadin.flow.spring.security.VaadinWebSecurity;
import com.vaadin.hilla.route.RouteUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.security.authorization.AuthorityAuthorizationManager;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig extends VaadinWebSecurity {
protected final Log logger = LogFactory.getLog(this.getClass());
private final RouteUtil routeUtil;
private final OAuth2LoginSuccessHandler oAuth2LoginSuccessHandler;
private final CustomUserAuthoritiesMapper customUserAuthoritiesMapper;
private final CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Value("${auth.secret}")
private String authSecret;
public SecurityConfig(RouteUtil routeUtil,
OAuth2LoginSuccessHandler oAuth2LoginSuccessHandler,
CustomUserAuthoritiesMapper customUserAuthoritiesMapper,
CustomAuthenticationFailureHandler customAuthenticationFailureHandler) {
this.routeUtil = routeUtil;
this.oAuth2LoginSuccessHandler = oAuth2LoginSuccessHandler;
this.customUserAuthoritiesMapper = customUserAuthoritiesMapper;
this.customAuthenticationFailureHandler = customAuthenticationFailureHandler;
}
/**
* Protects ALL methods (including inherited) in admin services - requires ADMIN role
* Using bean pattern which handles inheritance properly
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static Advisor protectAdminServices() {
AspectJExpressionPointcut pattern = new AspectJExpressionPointcut();
pattern.setExpression(
"bean(destinationService) || " +
"bean(sourceService) || " +
"bean(sourceAuthConfigService) || " +
"bean(userService) || " +
"bean(roleService)"
);
return new AuthorizationManagerBeforeMethodInterceptor(pattern,
AuthorityAuthorizationManager.hasRole("ADMIN"));
}
/**
* Protects ALL methods (including inherited) in user services - requires USER role or higher
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static Advisor protectUserServices() {
AspectJExpressionPointcut pattern = new AspectJExpressionPointcut();
pattern.setExpression("bean(prefectCredentialService)");
return new AuthorizationManagerBeforeMethodInterceptor(pattern,
AuthorityAuthorizationManager.hasAnyRole("USER", "ADMIN", "INTERNAL"));
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// First set up all the OAuth and security related paths
http.authorizeHttpRequests(registry -> registry
.requestMatchers(routeUtil::isRouteAllowed).permitAll()
.requestMatchers("/login").permitAll()
.requestMatchers("/login/oauth2/authorization/microsoft").permitAll()
.requestMatchers("/login/oauth2/authorization/google").permitAll()
.requestMatchers("/access-denied").permitAll()
.requestMatchers("/error").permitAll()
)
// Configure OAuth2 login with custom user authorities mapper
.oauth2Login(oauth2 -> oauth2
.loginPage("/login")
.successHandler(oAuth2LoginSuccessHandler)
.failureHandler(customAuthenticationFailureHandler)
.userInfoEndpoint(userInfo -> userInfo
.userAuthoritiesMapper(customUserAuthoritiesMapper)
)
);
// Default config to allow Vaadin paths
super.configure(http);
http.sessionManagement(httpSecuritySessionManagementConfigurer ->
httpSecuritySessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
setLoginView(http, "/login");
// Enable stateless authentication
setStatelessAuthentication(http,
new SecretKeySpec(Base64.getDecoder().decode(authSecret), JwsAlgorithms.HS256)
, "ai.goacquire.frontend"
, 43200);
}
}
After:
package ai.goacquire.frontend.config;
import ai.goacquire.frontend.security.CustomAuthenticationFailureHandler;
import ai.goacquire.frontend.security.CustomUserAuthoritiesMapper;
import ai.goacquire.frontend.security.OAuth2LoginSuccessHandler;
import com.vaadin.flow.spring.security.VaadinAwareSecurityContextHolderStrategyConfiguration;
import com.vaadin.flow.spring.security.stateless.VaadinStatelessSecurityConfigurer;
import com.vaadin.hilla.route.RouteUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Role;
import org.springframework.security.authorization.AuthorityAuthorizationManager;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
import org.springframework.security.web.SecurityFilterChain;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import static com.vaadin.flow.spring.security.VaadinSecurityConfigurer.vaadin;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@Import(VaadinAwareSecurityContextHolderStrategyConfiguration.class)
public class SecurityConfig {
protected final Log logger = LogFactory.getLog(this.getClass());
private final RouteUtil routeUtil;
private final OAuth2LoginSuccessHandler oAuth2LoginSuccessHandler;
private final CustomUserAuthoritiesMapper customUserAuthoritiesMapper;
private final CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Value("${auth.secret}")
private String authSecret;
public SecurityConfig(RouteUtil routeUtil,
OAuth2LoginSuccessHandler oAuth2LoginSuccessHandler,
CustomUserAuthoritiesMapper customUserAuthoritiesMapper,
CustomAuthenticationFailureHandler customAuthenticationFailureHandler) {
this.routeUtil = routeUtil;
this.oAuth2LoginSuccessHandler = oAuth2LoginSuccessHandler;
this.customUserAuthoritiesMapper = customUserAuthoritiesMapper;
this.customAuthenticationFailureHandler = customAuthenticationFailureHandler;
}
/**
* Protects ALL methods (including inherited) in admin services - requires ADMIN role
* Using bean pattern which handles inheritance properly
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static Advisor protectAdminServices() {
AspectJExpressionPointcut pattern = new AspectJExpressionPointcut();
pattern.setExpression(
"bean(destinationService) || " +
"bean(sourceService) || " +
"bean(sourceAuthConfigService) || " +
"bean(userService) || " +
"bean(roleService)"
);
return new AuthorizationManagerBeforeMethodInterceptor(pattern,
AuthorityAuthorizationManager.hasRole("ADMIN"));
}
/**
* Protects ALL methods (including inherited) in user services - requires USER role or higher
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static Advisor protectUserServices() {
AspectJExpressionPointcut pattern = new AspectJExpressionPointcut();
pattern.setExpression("bean(prefectCredentialService)");
return new AuthorizationManagerBeforeMethodInterceptor(pattern,
AuthorityAuthorizationManager.hasAnyRole("USER", "ADMIN", "INTERNAL"));
}
@Bean
public SecurityFilterChain vaadinSecurityFilterChain(HttpSecurity http) throws Exception {
// Configure authorization rules
http.authorizeHttpRequests(registry -> registry
.requestMatchers(routeUtil::isRouteAllowed).permitAll()
.requestMatchers("/login").permitAll()
.requestMatchers("/login/oauth2/authorization/microsoft").permitAll()
.requestMatchers("/login/oauth2/authorization/google").permitAll()
.requestMatchers("/access-denied").permitAll()
.requestMatchers("/error").permitAll()
);
// Configure OAuth2 login with custom user authorities mapper
http.oauth2Login(oauth2 -> oauth2
.loginPage("/login")
.successHandler(oAuth2LoginSuccessHandler)
.failureHandler(customAuthenticationFailureHandler)
.userInfoEndpoint(userInfo -> userInfo
.userAuthoritiesMapper(customUserAuthoritiesMapper)
)
);
// Configure session management for stateless
http.sessionManagement(sessionManagement ->
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
// Apply Vaadin-specific security configuration
http.with(vaadin(), vaadin ->
vaadin.loginView("/login", "/")
);
// Configure stateless authentication with JWT
http.with(new VaadinStatelessSecurityConfigurer<>(),
stateless -> stateless
.issuer("ai.goacquire.frontend")
.expiresIn(43200) // 12 hours in seconds
.withSecretKey()
.secretKey(
new SecretKeySpec(
Base64.getDecoder().decode(authSecret),
JwsAlgorithms.HS256
)
)
);
return http.build();
}
}
1 Like