DEV Community

Rajesh Mishra
Rajesh Mishra

Posted on • Originally published at howtostartprogramming.in

Spring Security filter chain explained with custom filters — Complete Guide

Spring Security filter chain explained with custom filters — Complete Guide

A practical, in-depth guide to Spring Security filter chain explained with custom filters with examples.

INTRO

When you spin up a Spring Boot application and slap @EnableWebSecurity on a config class, you instantly get a wall of default filters protecting every endpoint. It feels great until you need to insert your own authentication step, log request metadata, or short‑circuit a request based on a custom header. The default filter order is opaque, and trying to “just add a bean” often results in ClassCastException or a silent no‑op because the filter never runs where you expect it to.

That friction isn’t just an annoyance—it leads to security bugs that hide in production. A mis‑ordered filter can let an unauthenticated request slip past your JWT validator, or it can cause a legitimate user to be logged out on every request. The real problem is a lack of visibility and control over the Spring Security filter chain. Understanding how the chain is built, how Spring decides the order, and how to inject custom filters at the right spot is essential for any engineer who wants reliable, maintainable security.

In the full guide we peel back the abstraction layer, show you the exact sequence of built‑in filters, and walk through three real‑world scenarios where a custom filter is the right tool. By the end you’ll be able to add, replace, or remove filters without breaking the chain, and you’ll have a checklist to avoid the most common pitfalls.

WHAT YOU'LL LEARN

  • The anatomy of the default filter chain – a step‑by‑step breakdown of each built‑in filter, why it exists, and where it sits in the order.
  • How Spring assembles the chain – the role of SecurityFilterChain, HttpSecurity, and the FilterRegistrationBean in the bootstrapping process.
  • Creating a custom filter – extending OncePerRequestFilter, handling doFilterInternal, and accessing the SecurityContext.
  • Strategic placement – using addFilterBefore, addFilterAfter, and addFilterAt to position your filter relative to UsernamePasswordAuthenticationFilter, BearerTokenAuthenticationFilter, etc.
  • Replacing a built‑in filter – when and how to swap out BasicAuthenticationFilter with a bespoke implementation without losing downstream processing.
  • Production‑ready tips – idempotent registration, avoiding duplicate execution, and profiling the chain with Spring Boot Actuator.

A SHORT CODE SNIPPET

@Configuration
public class SecurityConfig {

@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.addFilterBefore(new RequestIdFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.oauth2ResourceServer(oauth -> oauth.jwt());
return http.build();
}
}
Enter fullscreen mode Exit fullscreen mode

The snippet injects a RequestIdFilter before the username/password authentication step, guaranteeing that every request carries a traceable ID for downstream logging.

KEY TAKEAWAYS

  • The filter chain is a deterministic list, not a magic bean forest; knowing the exact order lets you reason about security flow.
  • Use the addFilter* family of methods on HttpSecurity to control placement; never rely on @Component scanning alone for custom filters.
  • Replacing a default filter requires explicitly disabling the original (http.removeFilter(...)) to prevent duplicate processing.
  • Profiling the final chain with http.getFilters() or Actuator’s httptrace endpoint reveals hidden ordering issues before they hit production.

👉 Read the complete guide with step-by-step examples, common mistakes, and production tips:

Spring Security filter chain explained with custom filters — Complete Guide

Top comments (0)