Spring Security Filter Chain

At the heart of Spring Security's robust defense mechanism lies a carefully orchestrated filter chain. Understanding the overall architecture and execution flow of this filter chain is essential for mastering how authentication and authorization operate within your applications.

Following the Servlet specification, multiple filters can be chained together so that an incoming request passes through each one sequentially before finally reaching the target Servlet. Spring Security leverages this exact mechanism, breaking down core security concerns—such as authentication, authorization, CSRF protection, and session management—into a series of specialized security filters. These filters are arranged in a fixed, deliberate order to handle security checks before your business logic is ever invoked.

In a running application, three primary components collaborate to manage this process:

  • DelegatingFilterProxy: A bridge filter automatically registered by Spring Boot into the Servlet container, responsible for delegating incoming requests to the Spring container beans.
  • FilterChainProxy: The core dispatcher of Spring Security, which holds one or more SecurityFilterChain instances and selects the appropriate one based on the incoming request path.
  • SecurityFilterChain: A specific security filter chain consisting of several security filters ordered sequentially.
  1. As a request enters the Servlet container, it is first intercepted by the DelegatingFilterProxy and handed over to the FilterChainProxy.
  2. The FilterChainProxy iterates through all configured SecurityFilterChain instances, using a securityMatcher to determine which chain matches the current request. Note that a single request will only ever match and traverse one chain.
  3. Once a matching chain is found, its filters execute in a predefined order. For instance, a CSRF filter validates the request token, followed by authentication filters (such as form login or token-based filters) that attempt to establish the user's identity, culminating in authorization filters that make final access decisions.
  4. Upon successful authentication, user details are encapsulated into an Authentication object and stored within the security context for subsequent filters and business logic to consume.
  5. If an authentication or authorization exception occurs at any point, the exception translation filter catches it and redirects the user to a login page or returns an appropriate 401 or 403 status code.

Key Security Filters Overview

Spring Security comes with dozens of built-in filters. Some of the most frequently used include:

  • SecurityContextHolderFilter: Loads and clears the security context.
  • CsrfFilter: Defends against Cross-Site Request Forgery attacks.
  • UsernamePasswordAuthenticationFilter: Handles traditional form-based logins.
  • BearerTokenAuthenticationFilter: Processes token-based authentication like JWTs.
  • ExceptionTranslationFilter: Catches security-related exceptions thrown further down the line.
  • AuthorizationFilter: Serves as the final access control decision point.

The order of these filters is meticulously designed by the framework and should rarely be disrupted. The internal implementation details of individual filters are typically explored in dedicated discussions.

Multiple Filter Chains and Matching Rules

Real-world projects often feature multiple distinct endpoints: an administrative backend might require form-based login, while public APIs might rely on stateless JWT authentication. In such scenarios, you can define multiple SecurityFilterChain beans, each declaring its own matching paths and security policies:

@Bean
public SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
    http.securityMatcher("/api/**")
        .authorizeHttpRequests(a -> a.anyRequest().authenticated())
        .csrf(csrf -> csrf.disable())
        .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
    return http.build();
}

@Bean
public SecurityFilterChain defaultChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(a -> a.anyRequest().authenticated())
        .formLogin(Customizer.withDefaults());
    return http.build();
}

The FilterChainProxy evaluates these chains in the order they are declared, and the first matching chain takes effect. Therefore, more specific securityMatcher rules should always be placed first.

How to Extend the Filter Chain

  • Inserting Custom Filters: Using methods like addFilterBefore, addFilterAfter, or addFilterAt, you can slot custom filters into specific positions relative to standard filters. This is commonly used for parsing custom tokens or capturing audit logs.
  • Modifying Default Behavior: You can enable or disable built-in capabilities via the configuration DSL, such as disabling CSRF protection or customizing the login page URL.
  • Proper Registration: Custom security filters should always be integrated into the SecurityFilterChain using the aforementioned methods rather than being declared as standalone filter beans. Otherwise, Spring Boot might inadvertently register them directly with the Servlet container, causing the same filter to execute twice.

Comparison with Traditional Servlet Filters

  • Management: Standard filters are managed directly by the Servlet container, whereas security filters are orchestrated by the FilterChainProxy, giving them full access to Spring's dependency injection container.
  • Matching Flexibility: Traditional filters are typically restricted to coarse-grained URL matching, whereas SecurityFilterChain supports sophisticated request matchers based on path patterns, HTTP methods, and more.
  • Order Guarantees: The execution order of security filters is hardcoded and managed by the framework, while standard filter ordering must be manually maintained by the developer.

Conclusion

The filter chain serves as the structural backbone of Spring Security: the DelegatingFilterProxy acts as the entry point, the FilterChainProxy handles dispatching, and the SecurityFilterChain orchestrates the specific filters. By grasping this high-level perspective—how requests enter the chain, how chains are matched, and how filters are ordered and extended—you establish a solid foundation for exploring the inner workings of individual core filters and mastering Spring Security overall.