or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

authentication.mdindex.mdkotlin-dsl.mdmethod-security.mdoauth2.mdreactive-web-security.mdsaml2.mdservlet-web-security.md
tile.json

tessl/maven-spring-security-config

Spring Security configuration module providing declarative security configuration support for Spring applications

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.springframework.security/spring-security-config@7.0.x

To install, run

npx @tessl/cli install tessl/maven-spring-security-config@7.0.0

index.mddocs/

Spring Security Config

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.

Package Information

  • Package Name: spring-security-config
  • Package Coordinates: org.springframework.security:spring-security-config
  • Package Type: Maven (JAR)
  • Language: Java (with Kotlin DSL support)
  • Version: 7.0.0
  • Installation:
<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'

Dependencies

Spring Security Config requires:

  • Spring Framework 6.0+
  • Spring Security Core 7.0+
  • For reactive support: Project Reactor (reactor-core)

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>

Core Imports

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.invoke

Quick Start

Minimal Servlet-Based Web Security

import 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 @Bean
  • HttpSecurity parameter is automatically injected by Spring
  • build() must be called to finalize configuration
  • Throws Exception - handle or declare in method signature

Minimal Reactive Web Security (WebFlux)

import 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:

  • Reactive configuration does not throw checked exceptions
  • Use pathMatchers() instead of requestMatchers() for reactive
  • Use anyExchange() instead of anyRequest() for reactive

Method Security

import 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:

  • Method security requires AOP proxies (use @EnableMethodSecurity)
  • Annotations work on Spring-managed beans only
  • @PostAuthorize executes method first, then checks return value
  • Throws AccessDeniedException on authorization failure

Kotlin DSL

import 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:

  • Import org.springframework.security.config.annotation.web.invoke to enable DSL
  • DSL is type-safe and provides compile-time checking
  • All Java configuration options available in Kotlin DSL

Architecture

Spring Security Config is built around several key architectural components:

Configuration Model

  • @Enable Annotations: Activation annotations like @EnableWebSecurity and @EnableMethodSecurity enable different security features. These are meta-annotations that import configuration classes.
  • SecurityFilterChain: Modern approach uses @Bean methods that return SecurityFilterChain instances. Thread-safe once built.
  • Builder Pattern: All configuration uses fluent builders (HttpSecurity, ServerHttpSecurity, AuthenticationManagerBuilder). Builders are not thread-safe during configuration.
  • Customizer Pattern: Configuration uses Customizer<T> functional interface for clean, composable configuration. Thread-safe if underlying configuration is thread-safe.
  • Configurer Pattern: Individual features are configured via AbstractHttpConfigurer implementations that can be composed together.

Servlet vs Reactive

Spring Security Config supports both servlet-based (Spring MVC) and reactive (Spring WebFlux) applications:

  • Servlet: Uses HttpSecurity builder and produces SecurityFilterChain with servlet Filter instances. Filters execute synchronously in servlet container thread.
  • Reactive: Uses 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.

Authentication Architecture

  • AuthenticationManager: Central component for authentication. Thread-safe for concurrent authentication requests.
  • AuthenticationProvider: Pluggable authentication mechanisms. Must be thread-safe if used in concurrent scenarios.
  • UserDetailsService: Loads user-specific data. Must be thread-safe for concurrent access.
  • AuthenticationManagerBuilder: Fluent builder for configuring authentication. Not thread-safe during configuration.

Authorization Architecture

  • AuthorizationManager: Modern authorization decision API (Spring Security 5.6+). Thread-safe for concurrent authorization checks.
  • URL-based Authorization: Configure access rules for HTTP requests. Rules evaluated in order until match found.
  • Method Security: Use annotations like @PreAuthorize, @PostAuthorize on methods. Requires AOP proxies.
  • Expression-based Access Control: SpEL expressions for complex authorization logic. Expression evaluation is thread-safe.

Security Filter Chain

The security filter chain is composed of multiple servlet Filter instances (or WebFilter for reactive) that handle:

  1. Security context establishment (thread-local for servlet, reactive context for WebFlux)
  2. Authentication (synchronous for servlet, reactive for WebFlux)
  3. Authorization (evaluated in filter order)
  4. Session management (servlet only, reactive uses reactive session)
  5. CSRF protection (token-based validation)
  6. CORS handling (preflight and actual requests)
  7. Security headers (HTTP response headers)
  8. Exception handling (authentication and authorization failures)
  9. Logout processing (session invalidation, cookie deletion)

Filter Order: Filters execute in a specific order. Custom filters can be inserted at specific positions using addFilterBefore(), addFilterAfter(), or addFilterAt().

OAuth2 & SAML2 Support

Comprehensive support for modern authentication protocols:

  • OAuth2 Client: OAuth2/OIDC login and client functionality. Thread-safe for concurrent requests.
  • OAuth2 Resource Server: JWT and opaque token validation. Token validation is thread-safe.
  • OAuth2 Authorization Server: Full authorization server implementation. Thread-safe for concurrent authorization requests.
  • SAML2 Service Provider: SAML2 authentication and logout. Thread-safe for concurrent SSO requests.

Capabilities

Servlet Web Security

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:

  • URL-based authorization with authorizeHttpRequests() - rules evaluated in order
  • Authentication mechanisms (form login, HTTP Basic, OAuth2, SAML2, X.509, WebAuthn)
  • Session management and concurrent session control
  • CSRF and CORS protection
  • Security headers (CSP, HSTS, X-Frame-Options, etc.)
  • Exception handling and logout

Thread Safety:

  • HttpSecurity builder is not thread-safe during configuration
  • SecurityFilterChain is thread-safe after build
  • Filters in chain are thread-safe for concurrent requests

Performance Considerations:

  • Authorization rules evaluated in order - place most specific rules first
  • CSRF token validation adds ~0.1-0.5ms overhead per request
  • Session creation adds memory overhead - use STATELESS for stateless APIs
  • Security headers add minimal overhead (~0.05ms per request)

Servlet Web Security

Reactive Web Security

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:

  • Reactive authorization with authorizeExchange() - rules evaluated in order
  • Reactive authentication mechanisms
  • Reactive CSRF and CORS
  • Security headers for reactive applications
  • Reactive session management

Thread Safety:

  • ServerHttpSecurity builder is not thread-safe during configuration
  • SecurityWebFilterChain is thread-safe after build
  • WebFilters in chain are thread-safe for concurrent requests

Performance Considerations:

  • Reactive chains are non-blocking - better for high concurrency
  • Authorization rules evaluated in order - place most specific rules first
  • CSRF validation in reactive chain adds minimal overhead
  • No session overhead for stateless reactive applications

Reactive Web Security

OAuth2 Configuration

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:

  • OAuth2/OIDC login for single sign-on
  • OAuth2 client for accessing protected resources
  • JWT and opaque token resource server validation
  • Full OAuth2 authorization server with PKCE, device flow, client credentials, etc.
  • OIDC UserInfo, back-channel logout, front-channel logout

Thread Safety:

  • OAuth2 components are thread-safe for concurrent requests
  • Token validation is thread-safe
  • Authorization server is thread-safe for concurrent authorization requests

Performance Considerations:

  • JWT validation adds ~1-5ms overhead per request (depends on key size)
  • Opaque token introspection requires network call - adds latency
  • Token caching can improve performance for repeated validations

OAuth2 Configuration

SAML2 Configuration

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:

  • SAML2 authentication (Web Browser SSO Profile)
  • SAML2 single logout
  • SAML2 metadata endpoint
  • Integration with SAML2 Identity Providers

Thread Safety:

  • SAML2 components are thread-safe for concurrent SSO requests
  • Metadata generation is thread-safe

Performance Considerations:

  • SAML2 assertion validation adds ~2-10ms overhead
  • XML parsing and signature verification are CPU-intensive
  • Metadata caching improves performance

SAML2 Configuration

Method Security

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)
  • JSR-250 annotations (@RolesAllowed, @PermitAll, @DenyAll)

Thread Safety:

  • Method security advisors are thread-safe
  • SpEL expression evaluation is thread-safe
  • Authorization checks are thread-safe for concurrent method invocations

Performance Considerations:

  • AOP proxy creation adds minimal overhead (~0.01ms per method call)
  • SpEL expression evaluation adds ~0.1-1ms overhead (depends on complexity)
  • @PostAuthorize executes method first - may waste computation if authorization fails
  • Use @PreAuthorize when possible to fail fast

Method Security

Authentication Configuration

Configure 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:

  • In-memory user store
  • JDBC user store
  • Custom UserDetailsService
  • LDAP authentication
  • Custom AuthenticationProvider implementations

Thread Safety:

  • AuthenticationManagerBuilder is not thread-safe during configuration
  • Built AuthenticationManager is thread-safe for concurrent authentication requests
  • UserDetailsService implementations must be thread-safe
  • AuthenticationProvider implementations must be thread-safe

Performance Considerations:

  • In-memory authentication is fastest (~0.1ms)
  • JDBC authentication requires database query (~1-10ms depending on query)
  • LDAP authentication requires network call (~10-100ms)
  • Custom providers performance depends on implementation

Authentication Configuration

Kotlin DSL

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:

  • Servlet web security (HttpSecurity)
  • Reactive web security (ServerHttpSecurity)
  • RSocket security (RSocketSecurity)
  • All configurers (OAuth2, SAML2, CSRF, CORS, headers, etc.)

Thread Safety:

  • Same thread safety guarantees as Java configuration
  • DSL is compile-time checked - type-safe

Kotlin DSL

Multi-Factor Authentication

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:

  • Multiple factor requirements (password, OTT, biometric, etc.)
  • Integration with @EnableWebSecurity and @EnableMethodSecurity
  • Custom factor authorities via FactorGrantedAuthority
  • Note: Servlet applications only (reactive support planned)

Thread Safety:

  • MFA configuration is thread-safe
  • Factor validation is thread-safe for concurrent requests

Global Authentication Configuration

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.

WebSecurity Customization

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)
  • Built configuration is thread-safe

RSocket Security

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();
    }
}

WebSocket Security

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
}

Common Configuration Patterns

Multiple Security Filter Chains

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:

  • Use @Order annotation to control filter chain priority
  • Lower order value = higher priority (evaluated first)
  • Use securityMatcher() to limit which requests a chain applies to
  • Each chain is independent - configure authentication, CSRF, etc. per chain

Custom Authentication Provider

@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 use
  • supports() method determines which authentication types are handled
  • Throw AuthenticationException subclasses for authentication failures
  • Return fully authenticated Authentication object on success

Ignoring Certain Requests

@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()
);

CSRF with Cookie Repository

http.csrf(csrf -> csrf
    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);

Important Notes:

  • Cookie-based CSRF tokens enable JavaScript access
  • Use for Single Page Applications (SPAs)
  • withHttpOnlyFalse() allows JavaScript to read token
  • Token is automatically included in subsequent requests

Custom Security Headers

http.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)
    )
);

Types

Core Types

/**
 * 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);
}

Session Management Types

/**
 * 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
}

Authorization Types

/**
 * 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();
}

Configuration Customizer

/**
 * 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();
}

Error Handling

Common exceptions thrown during configuration and runtime:

Configuration Exceptions

  • IllegalStateException: Thrown when configuration is invalid or incomplete

    • Example: Calling build() without configuring required components
    • Solution: Ensure all required configuration is complete before calling build()
  • IllegalArgumentException: Thrown for invalid configuration parameters

    • Example: Passing null to methods that don't accept null
    • Solution: Validate parameters before passing to configuration methods
  • BeanCreationException: Thrown when security bean creation fails

    • Example: Circular dependency or missing required dependencies
    • Solution: Check bean dependencies and configuration order

Runtime Exceptions

  • AuthenticationException: Base exception for authentication failures

    • Subclasses: BadCredentialsException, AccountExpiredException, AccountLockedException, etc.
    • Solution: Handle in AuthenticationEntryPoint or exception handler
  • AccessDeniedException: Thrown when access is denied for authenticated users

    • Solution: Handle in AccessDeniedHandler or exception handler
  • CsrfException: Thrown when CSRF token validation fails

    • Solution: Ensure CSRF token is included in requests (form or header)

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");
            }
        })
    );

Thread Safety

Configuration Phase

  • Builders (HttpSecurity, ServerHttpSecurity, AuthenticationManagerBuilder): Not thread-safe during configuration. Configure in @Bean methods (single-threaded during application startup).
  • Customizers: Thread-safe if underlying configuration is thread-safe. Typically invoked during single-threaded configuration phase.

Runtime Phase

  • SecurityFilterChain: Thread-safe after build. Filters in chain must be thread-safe for concurrent requests.
  • SecurityWebFilterChain: Thread-safe after build. WebFilters in chain must be thread-safe for concurrent requests.
  • AuthenticationManager: Thread-safe for concurrent authentication requests.
  • AuthorizationManager: Must be thread-safe for concurrent authorization checks.
  • UserDetailsService: Must be thread-safe for concurrent access.
  • AuthenticationProvider: Must be thread-safe for concurrent use.

Best Practices:

  • Configure security in @Bean methods (single-threaded during startup)
  • Ensure all runtime components are thread-safe
  • Use immutable objects where possible
  • Synchronize access to mutable shared state

Performance Considerations

Configuration Performance

  • Builder Configuration: Negligible overhead during application startup
  • Filter Chain Building: Minimal overhead (~1-5ms) during startup
  • Bean Creation: Standard Spring bean creation overhead

Runtime Performance

  • Authorization Rule Evaluation: ~0.1-0.5ms per request (depends on number of rules)

    • Optimize: Place most specific rules first
    • Optimize: Use simple role checks instead of complex expressions when possible
  • CSRF Token Validation: ~0.1-0.5ms per request

    • Overhead: Token generation, storage, and validation
    • Optimize: Disable for stateless APIs (JWT, OAuth2 resource server)
  • Session Management: Memory overhead for session storage

    • Overhead: ~1-5KB per active session
    • Optimize: Use STATELESS policy for stateless APIs
  • Security Headers: ~0.05ms per request

    • Minimal overhead for header generation
  • Method Security: ~0.1-1ms per method call

    • Overhead: AOP proxy invocation + SpEL evaluation
    • Optimize: Use simple expressions, cache authorization decisions when appropriate
  • OAuth2 JWT Validation: ~1-5ms per request

    • Overhead: JWT parsing, signature verification, expiration check
    • Optimize: Cache JWT decoder, use local key validation
  • SAML2 Validation: ~2-10ms per request

    • Overhead: XML parsing, signature verification
    • Optimize: Cache metadata, use efficient XML parsers

Optimization Tips:

  1. Use STATELESS session policy for stateless APIs
  2. Disable CSRF for stateless APIs
  3. Place most specific authorization rules first
  4. Cache expensive operations (JWT keys, SAML metadata, user lookups)
  5. Use simple authorization checks when possible
  6. Minimize security filter chain length
  7. Use reactive security for high-concurrency scenarios

Troubleshooting

Issue: SecurityFilterChain not applied

Symptoms: Security configuration seems ignored, no authentication required.

Causes:

  1. Missing @EnableWebSecurity annotation
  2. SecurityFilterChain bean not found
  3. Wrong @Order value causing wrong chain to match
  4. securityMatcher() not matching requests

Solutions:

// 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
    // ...
}

Issue: CSRF token missing

Symptoms: POST requests fail with 403 Forbidden, CSRF token errors in logs.

Causes:

  1. CSRF token not included in form/request
  2. CSRF disabled but should be enabled
  3. Cookie-based CSRF token not accessible to JavaScript

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());

Issue: Method security not working

Symptoms: @PreAuthorize annotations ignored, no authorization checks.

Causes:

  1. Missing @EnableMethodSecurity annotation
  2. Method not on Spring-managed bean
  3. AOP proxy not created (self-invocation)
  4. Wrong annotation enabled flag

Solutions:

// 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
    }
}

Issue: Authentication always fails

Symptoms: Login fails even with correct credentials.

Causes:

  1. Password encoder mismatch
  2. UserDetailsService not configured
  3. AuthenticationProvider not registered
  4. Wrong password format

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();

Best Practices

  1. Use SecurityFilterChain beans: Prefer the modern bean-based approach over extending WebSecurityConfigurerAdapter (deprecated in Spring Security 5.7, removed in 6.0)

  2. Use Customizer.withDefaults(): For default configuration instead of empty lambdas - more explicit and maintainable

  3. Disable CSRF for stateless APIs: When using JWT tokens or OAuth2 resource server - CSRF is not needed for stateless authentication

  4. Use method security: For fine-grained, business-logic-level authorization - complements URL-based authorization

  5. Configure CORS properly: Use CorsConfigurationSource bean for centralized CORS configuration - avoid per-request configuration

  6. Enable HTTPS: Use requiresChannel() or HSTS headers for production - protect credentials in transit

  7. Use role hierarchies: Define role hierarchies when roles have implicit permissions - reduces configuration duplication

  8. Configure session management: Set appropriate SessionCreationPolicy for your use case - STATELESS for APIs, IF_REQUIRED for web apps

  9. Use password encoders: Never store plain-text passwords, use PasswordEncoder implementations - BCrypt recommended for most cases

  10. Test security configuration: Use Spring Security Test for integration testing - verify security rules work as expected

  11. Order authorization rules: Place most specific rules first - improves performance and prevents rule conflicts

  12. Handle exceptions properly: Configure custom AuthenticationEntryPoint and AccessDeniedHandler - provide appropriate responses for APIs vs web UI

  13. Use security matchers: Limit security filter chains to specific URL patterns - improves performance and clarity

  14. Avoid ignoring requests: Prefer permitAll() over WebSecurity.ignoring() - maintains security headers

  15. Document security rules: Comment complex authorization logic - helps maintenance and debugging

Additional Resources