Spring Security Config provides the configuration infrastructure for Spring Security, enabling developers to declaratively configure security features in Spring applications through Java-based configuration, Kotlin DSL, and XML namespace configuration (legacy). It offers fluent APIs and builder patterns for configuring authentication mechanisms, authorization rules, session management, CSRF protection, CORS, OAuth2, SAML2, and security filters for both servlet-based (Spring MVC) and reactive (Spring WebFlux) applications.
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>7.0.0</version>
</dependency>Gradle:
implementation 'org.springframework.security:spring-security-config:7.0.0'Spring Security Config requires:
Maven Dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>7.0.0</version>
</dependency>
<!-- For reactive support -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
</dependency>
</dependencies>Servlet Web Security (Spring MVC):
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.Customizer;
import org.springframework.security.web.SecurityFilterChain;Reactive Web Security (Spring WebFlux):
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;Method Security:
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.access.prepost.PreAuthorize;Multi-Factor Authentication:
import org.springframework.security.config.annotation.authorization.EnableMultiFactorAuthentication;
import org.springframework.security.core.authority.FactorGrantedAuthority;Global Authentication:
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;Kotlin DSL:
import org.springframework.security.config.annotation.web.invokeimport org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.httpBasic(Customizer.withDefaults())
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/")
);
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(
User.withUsername("user")
.password("{noop}password")
.roles("USER")
.build(),
User.withUsername("admin")
.password("{noop}admin")
.roles("USER", "ADMIN")
.build()
);
}
}Important Notes:
SecurityFilterChain bean method must be annotated with @BeanHttpSecurity parameter is automatically injected by Springbuild() must be called to finalize configurationException - handle or declare in method signatureimport org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
@Configuration
@EnableWebFluxSecurity
public class ReactiveSecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange(exchanges -> exchanges
.pathMatchers("/public/**").permitAll()
.anyExchange().authenticated()
)
.formLogin(Customizer.withDefaults())
.httpBasic(Customizer.withDefaults());
return http.build();
}
}Important Notes:
pathMatchers() instead of requestMatchers() for reactiveanyExchange() instead of anyRequest() for reactiveimport org.springframework.context.annotation.Configuration;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.stereotype.Service;
@Configuration
@EnableMethodSecurity
public class MethodSecurityConfig {
}
@Service
public class SecureService {
@PreAuthorize("hasRole('ADMIN')")
public void adminOnlyMethod() {
// Only accessible by users with ADMIN role
// Throws AccessDeniedException if authorization fails
}
@PreAuthorize("hasAuthority('READ_PRIVILEGE')")
public String readData() {
return "sensitive data";
}
@PostAuthorize("returnObject.owner == authentication.name")
public Document getDocument(Long id) {
// Method executes, then authorization check runs
// Throws AccessDeniedException if check fails
return documentRepository.findById(id);
}
}Important Notes:
@EnableMethodSecurity)@PostAuthorize executes method first, then checks return valueAccessDeniedException on authorization failureimport org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.invoke
import org.springframework.security.web.SecurityFilterChain
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain {
http {
authorizeHttpRequests {
authorize("/public/**", permitAll)
authorize("/admin/**", hasRole("ADMIN"))
authorize(anyRequest, authenticated)
}
formLogin { }
httpBasic { }
}
return http.build()
}
}Important Notes:
org.springframework.security.config.annotation.web.invoke to enable DSLSpring Security Config is built around several key architectural components:
@EnableWebSecurity and @EnableMethodSecurity enable different security features. These are meta-annotations that import configuration classes.@Bean methods that return SecurityFilterChain instances. Thread-safe once built.HttpSecurity, ServerHttpSecurity, AuthenticationManagerBuilder). Builders are not thread-safe during configuration.Customizer<T> functional interface for clean, composable configuration. Thread-safe if underlying configuration is thread-safe.AbstractHttpConfigurer implementations that can be composed together.Spring Security Config supports both servlet-based (Spring MVC) and reactive (Spring WebFlux) applications:
HttpSecurity builder and produces SecurityFilterChain with servlet Filter instances. Filters execute synchronously in servlet container thread.ServerHttpSecurity builder and produces SecurityWebFilterChain with reactive WebFilter instances. Filters execute in reactive chain with non-blocking operations.Both follow similar APIs but are adapted to their respective programming models. Do not mix servlet and reactive security configurations in the same application.
@PreAuthorize, @PostAuthorize on methods. Requires AOP proxies.The security filter chain is composed of multiple servlet Filter instances (or WebFilter for reactive) that handle:
Filter Order: Filters execute in a specific order. Custom filters can be inserted at specific positions using addFilterBefore(), addFilterAfter(), or addFilterAt().
Comprehensive support for modern authentication protocols:
Core servlet-based web security configuration using HttpSecurity builder. Provides fluent API for configuring authentication, authorization, CSRF, CORS, headers, session management, and security filters for Spring MVC applications.
/**
* Enables Spring Security for servlet-based applications.
* Imports WebSecurityConfiguration and related configuration classes.
* Thread-safe: Configuration classes are singleton beans.
*
* @since 3.2
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({WebSecurityConfiguration.class, SpringWebMvcImportSelector.class,
OAuth2ImportSelector.class, HttpSecurityConfiguration.class})
@EnableGlobalAuthentication
public @interface EnableWebSecurity {
/**
* Enable debug mode (prints detailed security filter chain information).
* Default: false
*/
boolean debug() default false;
}
/**
* Main builder for configuring servlet-based web security.
* Not thread-safe during configuration. Thread-safe after build() is called.
*
* @since 3.2
*/
public final class HttpSecurity extends
AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
implements SecurityBuilder<DefaultSecurityFilterChain>,
HttpSecurityBuilder<HttpSecurity> {
/**
* Configures URL-based authorization rules.
* Rules are evaluated in order until a match is found.
*
* @param customizer configuration customizer (must not be null)
* @return this HttpSecurity instance for method chaining
* @throws Exception if configuration fails
*/
public HttpSecurity authorizeHttpRequests(
Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry> customizer
) throws Exception;
/**
* Builds the SecurityFilterChain.
* Must be called to finalize configuration.
*
* @return configured SecurityFilterChain (never null)
* @throws Exception if configuration is invalid or incomplete
*/
public DefaultSecurityFilterChain build() throws Exception;
}Usage Pattern:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// Configure security
return http.build();
}
}Key configuration areas:
authorizeHttpRequests() - rules evaluated in orderThread Safety:
HttpSecurity builder is not thread-safe during configurationSecurityFilterChain is thread-safe after buildPerformance Considerations:
Reactive web security configuration using ServerHttpSecurity builder for Spring WebFlux applications. Provides reactive equivalents of servlet security features using Project Reactor.
/**
* Enables Spring Security for reactive WebFlux applications.
* Imports reactive security configuration classes.
* Thread-safe: Configuration classes are singleton beans.
*
* @since 5.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({ReactiveAuthenticationManagerConfiguration.class,
ServerHttpSecurityConfiguration.class,
WebFluxSecurityConfiguration.class,
ServerOAuth2SecurityConfiguration.class})
public @interface EnableWebFluxSecurity {
}
/**
* Main builder for configuring reactive web security.
* Not thread-safe during configuration. Thread-safe after build() is called.
*
* @since 5.0
*/
public class ServerHttpSecurity {
/**
* Configures reactive URL-based authorization rules.
* Rules are evaluated in order until a match is found.
*
* @param customizer configuration customizer (must not be null)
* @return this ServerHttpSecurity instance for method chaining
*/
public ServerHttpSecurity authorizeExchange(
Customizer<AuthorizeExchangeSpec> authorizeExchangeCustomizer
);
/**
* Builds the SecurityWebFilterChain.
* Must be called to finalize configuration.
*
* @return configured SecurityWebFilterChain (never null)
*/
public SecurityWebFilterChain build();
}Usage Pattern:
@Configuration
@EnableWebFluxSecurity
public class ReactiveSecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
// Configure security
return http.build();
}
}Key configuration areas:
authorizeExchange() - rules evaluated in orderThread Safety:
ServerHttpSecurity builder is not thread-safe during configurationSecurityWebFilterChain is thread-safe after buildPerformance Considerations:
Comprehensive OAuth2 and OpenID Connect (OIDC) support including OAuth2 client, resource server, and authorization server configuration.
/**
* Configures OAuth2 login for servlet applications.
* Thread-safe for concurrent authentication requests.
*
* @since 5.0
*/
public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>>
extends AbstractAuthenticationFilterConfigurer<B, OAuth2LoginConfigurer<B>,
OAuth2LoginAuthenticationFilter> {
/**
* Configures OAuth2 login with default settings.
* Requires ClientRegistrationRepository bean.
*
* @param customizer configuration customizer (must not be null)
* @return this configurer for method chaining
*/
public OAuth2LoginConfigurer<B> oauth2Login(
Customizer<OAuth2LoginConfigurer<B>> customizer
);
}
/**
* Configures OAuth2 resource server with JWT validation.
* Thread-safe for concurrent token validation.
*
* @since 5.1
*/
public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<OAuth2ResourceServerConfigurer<H>, H> {
/**
* Configures JWT token validation.
* Requires JwtDecoder bean or jwkSetUri configuration.
*
* @param customizer JWT configuration customizer (must not be null)
* @return this configurer for method chaining
*/
public OAuth2ResourceServerConfigurer<H> jwt(
Customizer<JwtConfigurer> jwtCustomizer
);
}Usage Examples:
// OAuth2 Login
http.oauth2Login(Customizer.withDefaults());
// OAuth2 Resource Server (JWT)
http.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
// OAuth2 Authorization Server
OAuth2AuthorizationServerConfigurer authzServer =
new OAuth2AuthorizationServerConfigurer();
http.with(authzServer, Customizer.withDefaults());Supports:
Thread Safety:
Performance Considerations:
SAML2 Service Provider configuration for enterprise single sign-on integration.
/**
* Configures SAML2 login for servlet applications.
* Thread-safe for concurrent SSO requests.
*
* @since 5.2
*/
public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
extends AbstractAuthenticationFilterConfigurer<B, Saml2LoginConfigurer<B>,
Saml2WebSsoAuthenticationFilter> {
/**
* Configures SAML2 login with default settings.
* Requires RelyingPartyRegistrationRepository bean.
*
* @param customizer configuration customizer (must not be null)
* @return this configurer for method chaining
*/
public Saml2LoginConfigurer<B> saml2Login(
Customizer<Saml2LoginConfigurer<B>> customizer
);
}Usage Examples:
// SAML2 Login
http.saml2Login(Customizer.withDefaults());
// SAML2 Logout
http.saml2Logout(Customizer.withDefaults());
// SAML2 Metadata
http.saml2Metadata(Customizer.withDefaults());Supports:
Thread Safety:
Performance Considerations:
Method-level authorization using annotations on service methods. Supports SpEL expressions for complex authorization logic. Available for both servlet and reactive applications.
/**
* Enables method-level security for servlet applications.
* Requires AOP support (Spring AOP or AspectJ).
* Thread-safe: Security advisors are thread-safe.
*
* @since 5.6
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({PrePostMethodSecurityConfiguration.class})
public @interface EnableMethodSecurity {
/**
* Enable @PreAuthorize/@PostAuthorize annotations.
* Default: true
*/
boolean prePostEnabled() default true;
/**
* Enable @Secured annotation (legacy).
* Default: false
*/
boolean securedEnabled() default false;
/**
* Enable JSR-250 annotations (@RolesAllowed, @PermitAll, @DenyAll).
* Default: false
*/
boolean jsr250Enabled() default false;
/**
* Use CGLIB proxies instead of JDK dynamic proxies.
* Default: false
*/
boolean proxyTargetClass() default false;
/**
* Advice mode (PROXY or ASPECTJ).
* Default: PROXY
*/
AdviceMode mode() default AdviceMode.PROXY;
}
/**
* Enables method-level security for reactive applications.
* Requires reactive AOP support.
* Thread-safe: Security advisors are thread-safe.
*
* @since 5.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(ReactiveMethodSecuritySelector.class)
public @interface EnableReactiveMethodSecurity {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
boolean useAuthorizationManager() default true;
}Usage Examples:
// Servlet applications
@Configuration
@EnableMethodSecurity(
prePostEnabled = true,
securedEnabled = false,
jsr250Enabled = false
)
public class MethodSecurityConfig {
}
// Reactive (WebFlux) applications
@Configuration
@EnableReactiveMethodSecurity
public class ReactiveMethodSecurityConfig {
}Annotation types:
@PreAuthorize - Check before method execution@PostAuthorize - Check after method execution@PreFilter - Filter method parameters@PostFilter - Filter return values@Secured - Role-based authorization (legacy)@RolesAllowed, @PermitAll, @DenyAll)Thread Safety:
Performance Considerations:
@PostAuthorize executes method first - may waste computation if authorization fails@PreAuthorize when possible to fail fastConfigure authentication mechanisms and user storage through AuthenticationManagerBuilder.
/**
* Builder for configuring AuthenticationManager.
* Not thread-safe during configuration. Thread-safe after build().
*
* @since 3.2
*/
public class AuthenticationManagerBuilder
extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder>
implements ProviderManagerBuilder<AuthenticationManagerBuilder> {
/**
* Configures in-memory user store.
* Useful for testing or simple applications.
*
* @return configurer for in-memory authentication (never null)
* @throws Exception if configuration fails
*/
public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>
inMemoryAuthentication() throws Exception;
/**
* Configures JDBC-based user store.
* Requires DataSource bean.
*
* @return configurer for JDBC authentication (never null)
* @throws Exception if configuration fails
*/
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder>
jdbcAuthentication() throws Exception;
/**
* Configures custom UserDetailsService.
* UserDetailsService must be thread-safe for concurrent access.
*
* @param userDetailsService the service to use (must not be null)
* @return configurer for UserDetailsService authentication (never null)
* @throws Exception if configuration fails
*/
public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T>
userDetailsService(T userDetailsService) throws Exception;
/**
* Adds custom AuthenticationProvider.
* AuthenticationProvider must be thread-safe for concurrent use.
*
* @param authenticationProvider the provider to add (must not be null)
* @return this builder for method chaining
*/
public AuthenticationManagerBuilder authenticationProvider(
AuthenticationProvider authenticationProvider
);
/**
* Builds the AuthenticationManager.
* Must be called to finalize configuration.
*
* @return configured AuthenticationManager (never null)
* @throws Exception if configuration is invalid or incomplete
*/
public AuthenticationManager build() throws Exception;
}Supports:
Thread Safety:
AuthenticationManagerBuilder is not thread-safe during configurationAuthenticationManager is thread-safe for concurrent authentication requestsUserDetailsService implementations must be thread-safeAuthenticationProvider implementations must be thread-safePerformance Considerations:
Type-safe Kotlin DSL for all configuration options. Provides idiomatic Kotlin syntax for Spring Security configuration.
/**
* Extension function to enable Kotlin DSL for HttpSecurity.
* Import org.springframework.security.config.annotation.web.invoke to use.
* Thread-safe: Same as Java configuration.
*
* @param httpConfiguration DSL configuration block
* @return configured HttpSecurity instance
*/
fun HttpSecurity.invoke(httpConfiguration: HttpSecurityDsl.() -> Unit): HttpSecurity
/**
* Main DSL class for HttpSecurity configuration.
* Provides type-safe configuration methods.
*/
class HttpSecurityDsl {
fun authorizeHttpRequests(authorizeHttpRequestsConfig: AuthorizeHttpRequestsDsl.() -> Unit)
fun formLogin(formLoginConfig: FormLoginDsl.() -> Unit)
fun httpBasic(httpBasicConfig: HttpBasicDsl.() -> Unit)
fun oauth2Login(oauth2LoginConfig: OAuth2LoginDsl.() -> Unit)
fun oauth2ResourceServer(oauth2ResourceServerConfig: OAuth2ResourceServerDsl.() -> Unit)
fun csrf(csrfConfig: CsrfDsl.() -> Unit)
fun cors(corsConfig: CorsDsl.() -> Unit)
// ... other configurers
}Usage Example:
http {
authorizeHttpRequests {
authorize("/public/**", permitAll)
authorize(anyRequest, authenticated)
}
formLogin { }
oauth2Login { }
csrf { }
}Available for:
HttpSecurity)ServerHttpSecurity)RSocketSecurity)Thread Safety:
Enables MFA support requiring multiple authentication factors (e.g., password + one-time token).
/**
* Enables multi-factor authentication support.
* Requires multiple authentication factors to be satisfied.
* Thread-safe: Configuration is thread-safe.
*
* @since 7.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MultiFactorAuthenticationConfiguration.class)
public @interface EnableMultiFactorAuthentication {
/**
* Required authentication factors.
* All factors must be satisfied for authentication to succeed.
*
* @return array of required factor authorities
*/
FactorGrantedAuthority[] authorities();
}Usage Example:
@Configuration
@EnableMultiFactorAuthentication(authorities = {
FactorGrantedAuthority.FACTOR_PASSWORD,
FactorGrantedAuthority.FACTOR_OTT
})
public class MfaConfig {
}Supports:
@EnableWebSecurity and @EnableMethodSecurityFactorGrantedAuthorityThread Safety:
Enables global AuthenticationManagerBuilder configuration for sharing authentication across multiple security configurations.
/**
* Enables global AuthenticationManagerBuilder configuration.
* Allows sharing authentication configuration across multiple security filter chains.
* Thread-safe: Configuration is thread-safe.
*
* @since 3.2
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(AuthenticationConfiguration.class)
public @interface EnableGlobalAuthentication {
}Usage Example:
@Configuration
@EnableGlobalAuthentication
public class GlobalAuthConfig {
@Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(/* users */);
}
}Note: @EnableWebSecurity and @EnableMethodSecurity are already annotated with @EnableGlobalAuthentication, so this annotation is typically only needed for standalone authentication configuration.
Configure global web security settings and ignore certain requests entirely (bypass the security filter chain).
/**
* Functional interface for customizing WebSecurity.
* Thread-safe: Customizer is invoked during configuration.
*
* @since 4.2
*/
@FunctionalInterface
public interface WebSecurityCustomizer {
/**
* Customizes WebSecurity configuration.
*
* @param web the WebSecurity instance to customize (must not be null)
*/
void customize(WebSecurity web);
}
/**
* Builder for global web security configuration.
* Not thread-safe during configuration.
*
* @since 4.2
*/
public final class WebSecurity {
/**
* Configures requests to ignore (bypass security filter chain).
* WARNING: Ignored requests bypass ALL security, including headers.
*
* @return configurer for ignored requests (never null)
*/
public IgnoredRequestConfigurer ignoring();
/**
* Sets custom HTTP firewall.
*
* @param httpFirewall the firewall to use (must not be null)
* @return this WebSecurity instance for method chaining
*/
public WebSecurity httpFirewall(HttpFirewall httpFirewall);
/**
* Sets request rejected handler.
*
* @param requestRejectedHandler the handler to use (must not be null)
* @return this WebSecurity instance for method chaining
*/
public WebSecurity requestRejectedHandler(RequestRejectedHandler requestRejectedHandler);
/**
* Enables or disables debug mode.
*
* @param debug true to enable debug mode
* @return this WebSecurity instance for method chaining
*/
public WebSecurity debug(boolean debug);
}Usage Examples:
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring()
.requestMatchers("/resources/**", "/static/**", "/webjars/**");
}
// Enable debug mode
@Bean
public WebSecurityCustomizer debugCustomizer() {
return (web) -> web.debug(true);
}
// Custom HTTP firewall
@Bean
public WebSecurityCustomizer firewallCustomizer() {
return (web) -> web.httpFirewall(new StrictHttpFirewall());
}Important: Ignoring requests via WebSecurity.ignoring() means they completely bypass Spring Security, including security headers. For most use cases, prefer using permitAll() in HttpSecurity instead.
Thread Safety:
WebSecurityCustomizer is invoked during configuration (not thread-safe)Security configuration for RSocket protocol with support for various authentication mechanisms.
/**
* Enables RSocket security.
* Thread-safe: Configuration is thread-safe.
*
* @since 5.2
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(RSocketSecurityConfiguration.class)
public @interface EnableRSocketSecurity {
}
/**
* Builder for RSocket security configuration.
* Not thread-safe during configuration.
*
* @since 5.2
*/
public class RSocketSecurity {
/**
* Configures authorization for RSocket payloads.
*
* @param customizer authorization configuration customizer (must not be null)
* @return this RSocketSecurity instance for method chaining
*/
public RSocketSecurity authorizePayload(authorizePayload: Customizer<AuthorizePayloadsSpec>);
}Usage Example:
@Configuration
@EnableRSocketSecurity
public class RSocketSecurityConfig {
@Bean
public PayloadSocketAcceptorInterceptor authorization(RSocketSecurity security) {
security.authorizePayload(authorize -> authorize
.anyRequest().authenticated()
.anyExchange().permitAll()
);
return security.build();
}
}Security configuration for WebSocket connections (Spring Security 7.0+).
/**
* Enables WebSocket security.
* Thread-safe: Configuration is thread-safe.
*
* @since 7.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(WebSocketSecurityConfiguration.class)
public @interface EnableWebSocketSecurity {
}Usage Example:
@Configuration
@EnableWebSocketSecurity
public class WebSocketSecurityConfig {
// WebSocket security is automatically configured
// Use Spring Security Messaging for message-level security
}Configure different security policies for different URL patterns:
@Configuration
@EnableWebSecurity
public class MultiHttpSecurityConfig {
@Bean
@Order(1) // Lower order = higher priority
public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/api/**") // Only applies to /api/** requests
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
.csrf(csrf -> csrf.disable()); // Stateless API - disable CSRF
return http.build();
}
@Bean
@Order(2) // Higher order = lower priority
public SecurityFilterChain webFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.csrf(Customizer.withDefaults()); // Web UI - enable CSRF
return http.build();
}
}Important Notes:
@Order annotation to control filter chain prioritysecurityMatcher() to limit which requests a chain applies to@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
// Custom authentication logic
if (isValidUser(username, password)) {
List<GrantedAuthority> authorities = getAuthorities(username);
return new UsernamePasswordAuthenticationToken(
username, password, authorities
);
}
throw new BadCredentialsException("Invalid credentials");
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class
.isAssignableFrom(authentication);
}
}
@Bean
public SecurityFilterChain filterChain(
HttpSecurity http,
CustomAuthenticationProvider authProvider) throws Exception {
http
.authenticationProvider(authProvider) // Register custom provider
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}Important Notes:
AuthenticationProvider must be thread-safe for concurrent usesupports() method determines which authentication types are handledAuthenticationException subclasses for authentication failuresAuthentication object on success@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring()
.requestMatchers("/resources/**", "/static/**");
}Important: Ignored requests bypass ALL security, including security headers. Prefer permitAll() for most cases:
// Better approach - still applies security headers
http.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/resources/**", "/static/**").permitAll()
);http.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);Important Notes:
withHttpOnlyFalse() allows JavaScript to read tokenhttp.headers(headers -> headers
.contentSecurityPolicy(csp -> csp
.policyDirectives("default-src 'self'; script-src 'self' 'unsafe-inline'")
)
.frameOptions(frame -> frame.sameOrigin())
.httpStrictTransportSecurity(hsts -> hsts
.maxAgeInSeconds(31536000)
.includeSubDomains(true)
)
);/**
* Functional interface for configuration customization.
* Thread-safe if underlying configuration is thread-safe.
*
* @param <T> the type to customize
* @since 5.1
*/
@FunctionalInterface
public interface Customizer<T> {
/**
* Customizes the given object.
*
* @param t the object to customize (must not be null)
*/
void customize(T t);
/**
* Returns a Customizer that does nothing (uses defaults).
*
* @param <T> the type to customize
* @return a no-op customizer (never null)
*/
static <T> Customizer<T> withDefaults() {
return (t) -> {};
}
}
/**
* Interface for building security objects.
* Not thread-safe during build. Thread-safe after build().
*
* @param <O> the type of object being built
* @since 3.2
*/
public interface SecurityBuilder<O> {
/**
* Builds the security object.
*
* @return the built object (never null)
* @throws Exception if build fails
*/
O build() throws Exception;
}
/**
* Interface for configuring security builders.
* Not thread-safe during configuration.
*
* @param <O> the type of object being configured
* @param <B> the type of builder
* @since 3.2
*/
public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {
/**
* Initialize the configurer.
*
* @param builder the builder to initialize (must not be null)
* @throws Exception if initialization fails
*/
void init(B builder) throws Exception;
/**
* Configure the builder.
*
* @param builder the builder to configure (must not be null)
* @throws Exception if configuration fails
*/
void configure(B builder) throws Exception;
}
/**
* Base class for HTTP configurers.
* Provides common functionality for HTTP security configuration.
* Not thread-safe during configuration.
*
* @param <T> the configurer type
* @param <B> the builder type
* @since 3.2
*/
public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T, B>,
B extends HttpSecurityBuilder<B>>
extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, B> {
/**
* Disables this configurer.
*
* @return the builder for method chaining
*/
public B disable();
/**
* Adds object post-processor for customization.
*
* @param objectPostProcessor the post-processor to add (must not be null)
* @return this configurer for method chaining
*/
public T withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor);
}
/**
* Functional interface for post-processing security objects.
* Thread-safe if implementation is thread-safe.
*
* @param <T> the type of object to post-process
* @since 3.2
*/
@FunctionalInterface
public interface ObjectPostProcessor<T> {
/**
* Post-processes the given object.
*
* @param object the object to post-process (must not be null)
* @return the post-processed object (may be same instance or new instance)
*/
<O extends T> O postProcess(O object);
}/**
* Policy for session creation.
* Thread-safe enum.
*
* @since 3.1
*/
public enum SessionCreationPolicy {
/**
* Always create an HttpSession.
* Use when session state is required.
*/
ALWAYS,
/**
* Never create an HttpSession, but use one if it exists.
* Use when session is optional.
*/
NEVER,
/**
* Create an HttpSession only if required (default).
* Use for most web applications.
*/
IF_REQUIRED,
/**
* Never create an HttpSession and never use one.
* Use for stateless APIs (REST, JWT, etc.).
*/
STATELESS
}/**
* Interface for making authorization decisions.
* Must be thread-safe for concurrent use.
*
* @param <T> the type of object to authorize
* @since 5.6
*/
@FunctionalInterface
public interface AuthorizationManager<T> {
/**
* Checks if access should be granted.
*
* @param authentication supplier of authentication (must not be null)
* @param object the object to authorize (must not be null)
* @return authorization decision (never null)
*/
AuthorizationDecision check(
Supplier<Authentication> authentication,
T object
);
}
/**
* Result of an authorization decision.
* Immutable and thread-safe.
*
* @since 5.6
*/
public class AuthorizationDecision {
private final boolean granted;
/**
* Creates a new authorization decision.
*
* @param granted true if access is granted
*/
public AuthorizationDecision(boolean granted);
/**
* Returns whether access is granted.
*
* @return true if access is granted
*/
public boolean isGranted();
}/**
* Functional interface for web security customization.
* Thread-safe: Customizer is invoked during configuration.
*
* @since 4.2
*/
@FunctionalInterface
public interface WebSecurityCustomizer {
/**
* Customizes WebSecurity configuration.
*
* @param web the WebSecurity instance to customize (must not be null)
*/
void customize(WebSecurity web);
}
/**
* Defaults for granted authority configuration.
* Immutable and thread-safe.
*
* @since 5.0
*/
public class GrantedAuthorityDefaults {
private final String rolePrefix;
/**
* Creates new defaults with specified role prefix.
*
* @param rolePrefix the role prefix (typically "ROLE_")
*/
public GrantedAuthorityDefaults(String rolePrefix);
/**
* Returns the role prefix.
*
* @return the role prefix (never null)
*/
public String getRolePrefix();
}Common exceptions thrown during configuration and runtime:
IllegalStateException: Thrown when configuration is invalid or incomplete
build() without configuring required componentsbuild()IllegalArgumentException: Thrown for invalid configuration parameters
BeanCreationException: Thrown when security bean creation fails
AuthenticationException: Base exception for authentication failures
BadCredentialsException, AccountExpiredException, AccountLockedException, etc.AuthenticationEntryPoint or exception handlerAccessDeniedException: Thrown when access is denied for authenticated users
AccessDeniedHandler or exception handlerCsrfException: Thrown when CSRF token validation fails
Configure Custom Error Handling:
http
.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint((request, response, ex) -> {
// Handle unauthenticated requests
if (request.getRequestURI().startsWith("/api/")) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"error\":\"Unauthorized\"}");
} else {
response.sendRedirect("/login");
}
})
.accessDeniedHandler((request, response, ex) -> {
// Handle access denied
if (request.getRequestURI().startsWith("/api/")) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.getWriter().write("{\"error\":\"Forbidden\"}");
} else {
response.sendRedirect("/access-denied");
}
})
);HttpSecurity, ServerHttpSecurity, AuthenticationManagerBuilder): Not thread-safe during configuration. Configure in @Bean methods (single-threaded during application startup).Best Practices:
@Bean methods (single-threaded during startup)Authorization Rule Evaluation: ~0.1-0.5ms per request (depends on number of rules)
CSRF Token Validation: ~0.1-0.5ms per request
Session Management: Memory overhead for session storage
STATELESS policy for stateless APIsSecurity Headers: ~0.05ms per request
Method Security: ~0.1-1ms per method call
OAuth2 JWT Validation: ~1-5ms per request
SAML2 Validation: ~2-10ms per request
Optimization Tips:
STATELESS session policy for stateless APIsSymptoms: Security configuration seems ignored, no authentication required.
Causes:
@EnableWebSecurity annotationSecurityFilterChain bean not found@Order value causing wrong chain to matchsecurityMatcher() not matching requestsSolutions:
// Ensure @EnableWebSecurity is present
@Configuration
@EnableWebSecurity // Required!
public class SecurityConfig {
@Bean // Required!
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// Configuration
return http.build(); // Must call build()
}
}
// Check filter chain order
@Bean
@Order(1) // Lower order = higher priority
public SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
http.securityMatcher("/api/**"); // Ensure matcher is correct
// ...
}Symptoms: POST requests fail with 403 Forbidden, CSRF token errors in logs.
Causes:
Solutions:
// For forms - include CSRF token
<form method="post">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<!-- form fields -->
</form>
// For SPAs - use cookie-based CSRF
http.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);
// For stateless APIs - disable CSRF
http.csrf(csrf -> csrf.disable());Symptoms: @PreAuthorize annotations ignored, no authorization checks.
Causes:
@EnableMethodSecurity annotationSolutions:
// Ensure @EnableMethodSecurity is present
@Configuration
@EnableMethodSecurity // Required!
public class MethodSecurityConfig {
}
// Ensure method is on Spring bean
@Service // Must be Spring-managed
public class SecureService {
@PreAuthorize("hasRole('ADMIN')")
public void secureMethod() {
// Works - called through proxy
}
public void caller() {
secureMethod(); // Bypasses security - self-invocation!
// Use self-injection or external call
}
}Symptoms: Login fails even with correct credentials.
Causes:
Solutions:
// Ensure password encoder matches
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// Ensure UserDetailsService uses same encoder
@Bean
public UserDetailsService userDetailsService(PasswordEncoder encoder) {
return new InMemoryUserDetailsManager(
User.withUsername("user")
.password(encoder.encode("password")) // Encode password
.roles("USER")
.build()
);
}
// Or use password prefix
User.withUsername("user")
.password("{bcrypt}$2a$10$...") // Pre-encoded with prefix
.roles("USER")
.build();Use SecurityFilterChain beans: Prefer the modern bean-based approach over extending WebSecurityConfigurerAdapter (deprecated in Spring Security 5.7, removed in 6.0)
Use Customizer.withDefaults(): For default configuration instead of empty lambdas - more explicit and maintainable
Disable CSRF for stateless APIs: When using JWT tokens or OAuth2 resource server - CSRF is not needed for stateless authentication
Use method security: For fine-grained, business-logic-level authorization - complements URL-based authorization
Configure CORS properly: Use CorsConfigurationSource bean for centralized CORS configuration - avoid per-request configuration
Enable HTTPS: Use requiresChannel() or HSTS headers for production - protect credentials in transit
Use role hierarchies: Define role hierarchies when roles have implicit permissions - reduces configuration duplication
Configure session management: Set appropriate SessionCreationPolicy for your use case - STATELESS for APIs, IF_REQUIRED for web apps
Use password encoders: Never store plain-text passwords, use PasswordEncoder implementations - BCrypt recommended for most cases
Test security configuration: Use Spring Security Test for integration testing - verify security rules work as expected
Order authorization rules: Place most specific rules first - improves performance and prevents rule conflicts
Handle exceptions properly: Configure custom AuthenticationEntryPoint and AccessDeniedHandler - provide appropriate responses for APIs vs web UI
Use security matchers: Limit security filter chains to specific URL patterns - improves performance and clarity
Avoid ignoring requests: Prefer permitAll() over WebSecurity.ignoring() - maintains security headers
Document security rules: Comment complex authorization logic - helps maintenance and debugging