skip to content

FilterChainProxy & SecurityFilterChain

FilterChainProxy holds several SecurityFilterChains and picks the first whose matcher accepts the request, then runs only that chain. Interviewers ask about multiple chains for an API plus a UI, and about why order matters so much.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is FilterChainProxy in Spring Security, and what is its job?

level: juniorimportance: must knowfreq 60%

answer

  1. one servlet filter to rule them all
  2. springSecurityFilterChain bean via DelegatingFilterProxy
  3. holds List<SecurityFilterChain>
  4. first matching chain wins
  5. dispatcher, not a security filter itself

basics

~10 s

FilterChainProxy is the single servlet filter Spring Security registers. For each request it picks the first matching SecurityFilterChain and runs that chain's security filters in order.

solid answer

~30 s

FilterChainProxy is the one servlet Filter that Spring Security inserts into the servlet container's filter pipeline (bean name springSecurityFilterChain, reached via DelegatingFilterProxy). It does not do security itself; it holds an ordered List<SecurityFilterChain>, and on every request it walks that list, asks each chain matches(request), and delegates to the first one that matches. That chain's filters (e.g. authentication, CSRF, authorization) then execute in order. This design means all Spring Security's per-request logic funnels through a single entry point, which centralizes ordering, matching, and firewall/HttpFirewall enforcement, instead of scattering many filters directly in web.xml or the container config.

code

java · 14 lines
java
// FilterChainProxy is created for you; conceptually it does:
// for (SecurityFilterChain chain : chains) {
//     if (chain.matches(request)) {
//         return chain.getFilters(); // run these, then continue original chain
//     }
// }

// You normally never build it directly. You declare SecurityFilterChain beans:
@Bean
SecurityFilterChain appChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(a -> a.anyRequest().authenticated())
        .formLogin(Customizer.withDefaults());
    return http.build(); // returns a SecurityFilterChain that FilterChainProxy holds
}

go deeper

for a junior

Know it's the single security filter entry point that picks a chain and runs its filters.

for a middle

Explain the DelegatingFilterProxy bridge and the List<SecurityFilterChain> + first-match dispatch.

for a senior

Discuss HttpFirewall enforcement and why one entry point centralizes ordering/matching.

for a principal

Tie it to multi-chain architectures (API vs UI) and the operational consequences of the single dispatcher.

## The big picture A servlet container (Tomcat, Jetty) runs each request through a chain of `jakarta.servlet.Filter` objects before it reaches your controller/servlet. Spring Security needs to run its own filters (for authentication, CSRF, authorization, etc.), but instead of registering dozens of individual filters with the container, it registers exactly **one**: `FilterChainProxy`. ### How it gets into the container - Spring exposes a bean named `springSecurityFilterChain` (this bean is a `FilterChainProxy`). - A `DelegatingFilterProxy` is registered with the servlet container. `DelegatingFilterProxy` is a thin bridge: the container knows about it, and it looks up the `springSecurityFilterChain` bean from the Spring `ApplicationContext` and delegates every request to it. This lets the actual security filter be a fully Spring-managed bean (with dependency injection) even though the container instantiates filters itself. ### What FilterChainProxy holds `FilterChainProxy` contains an **ordered `List<SecurityFilterChain>`**. A `SecurityFilterChain` is a simple interface with two methods: ```java boolean matches(HttpServletRequest request); List<Filter> getFilters(); ``` - `matches(...)` uses a `RequestMatcher` to decide whether this chain applies to the current request. - `getFilters()` returns the ordered list of security filters for that chain. ### Per-request behavior For each incoming request, `FilterChainProxy`: 1. Applies the `HttpFirewall` (rejects malformed/dangerous requests early). 2. Iterates its `List<SecurityFilterChain>` in order and calls `matches(request)` on each. 3. Selects the **first** chain whose `matches` returns true — **only one chain ever handles a request**. 4. Runs that chain's filters in order (via an internal `VirtualFilterChain`), then hands control back to the container's original filter chain so the request reaches the controller. ### Why this design - Single, well-defined entry point for all security logic. - Central place to enforce ordering and the request firewall. - Multiple independent `SecurityFilterChain`s can coexist (e.g. one for `/api/**` stateless JWT, one for the browser UI with sessions and CSRF). ### Gotchas - FilterChainProxy is **not** the same as an individual filter like `UsernamePasswordAuthenticationFilter` — it is the container/dispatcher of chains. - If no chain matches a request, no security filters run for it (the request just continues down the container's filter chain). In practice you almost always have a catch-all chain so this doesn't accidentally happen.

  • What is DelegatingFilterProxy and why is it needed?
    It's a container-registered filter that delegates each request to a Spring-managed bean (the springSecurityFilterChain / FilterChainProxy). It bridges the servlet container, which instantiates filters itself, to the Spring ApplicationContext so the real filter can be a DI-wired bean.
  • Does FilterChainProxy itself authenticate or authorize requests?
    No. It only selects the matching SecurityFilterChain and invokes that chain's filters. The actual authentication/authorization work is done by individual filters inside the chain (e.g. AuthorizationFilter, UsernamePasswordAuthenticationFilter).

saying these in an interview costs you the question

  • Claiming Spring Security registers many separate filters directly with the container (it registers one FilterChainProxy).
  • Confusing FilterChainProxy with a single security filter like UsernamePasswordAuthenticationFilter.
  • Saying all SecurityFilterChains run for every request (only the first matching one runs).

context

open as a page

How does FilterChainProxy decide which SecurityFilterChain handles a given request?

level: middleimportance: must knowfreq 55%

basics

~10 s

It iterates its ordered list of SecurityFilterChains and calls each chain's matches(request), which uses a RequestMatcher. The first chain that matches is used; the rest are ignored.

open as a page

What RequestMatcher does a SecurityFilterChain use if you never call securityMatcher, and why does that matter?

level: middleimportance: should knowfreq 30%

basics

~10 s

It uses AnyRequestMatcher, so the chain matches every request. That makes it a catch-all, which must be ordered last or it will shadow more specific chains.

open as a page

Once a SecurityFilterChain is selected, how are its filters actually invoked? Explain VirtualFilterChain.

level: seniorimportance: should knowfreq 35%

basics

~10 s

FilterChainProxy wraps the selected chain's filters in a VirtualFilterChain. Each filter calls chain.doFilter(...) to advance; after the last security filter, it delegates back to the container's original FilterChain to reach the controller.

open as a page

You need a stateless JWT API and a session-based server-rendered UI in the same app. How do you structure the SecurityFilterChains, and what ordering pitfalls apply?

level: principalimportance: should knowfreq 30%

basics

~10 s

Define two SecurityFilterChain beans: one with securityMatcher("/api/**"), stateless + JWT + CSRF off, ordered first; one catch-all with sessions + form login + CSRF, ordered last. Order matters because the first matching chain wins.

open as a page