Spring Boot
WebSecurityConfigurerAdapter
Spring Security
Java
Multiple Configurations

Using multiple WebSecurityConfigurerAdapter in spring boot

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Older Spring Security applications sometimes used multiple WebSecurityConfigurerAdapter classes to apply different rules to different URL spaces. That pattern did work, but it is now legacy. In current Spring Security, the modern equivalent is multiple SecurityFilterChain beans with explicit ordering and request matching.

What the old pattern was trying to solve

The goal was usually one of these:

  • one security policy for /api/**
  • another policy for /admin/**
  • a different login flow for browser pages
  • open access for public endpoints

In the WebSecurityConfigurerAdapter era, developers handled this by defining multiple adapter classes with @Order. Each one matched a subset of requests.

That design idea still exists. The implementation style changed.

The modern Spring Security approach is multiple filter chains

Instead of multiple adapters, define multiple SecurityFilterChain beans. Each chain applies to the requests matched by its securityMatcher, and ordering decides which one gets a chance first.

java
1import org.springframework.context.annotation.Bean;
2import org.springframework.context.annotation.Configuration;
3import org.springframework.core.annotation.Order;
4import org.springframework.security.config.Customizer;
5import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6import org.springframework.security.web.SecurityFilterChain;
7
8@Configuration
9public class SecurityConfig {
10
11    @Bean
12    @Order(1)
13    SecurityFilterChain apiSecurity(HttpSecurity http) throws Exception {
14        http
15            .securityMatcher("/api/**")
16            .authorizeHttpRequests(auth -> auth.anyRequest().hasRole("API"))
17            .httpBasic(Customizer.withDefaults())
18            .csrf(csrf -> csrf.disable());
19        return http.build();
20    }
21
22    @Bean
23    @Order(2)
24    SecurityFilterChain webSecurity(HttpSecurity http) throws Exception {
25        http
26            .authorizeHttpRequests(auth -> auth
27                .requestMatchers("/login", "/public/**").permitAll()
28                .anyRequest().authenticated()
29            )
30            .formLogin(Customizer.withDefaults());
31        return http.build();
32    }
33}

This is the current way to express the same concept that multiple adapters used to express.

Order and matcher design matter

The first matching filter chain wins. That means your more specific matchers should usually come first.

A good rule is:

  • most specific chain first
  • catch-all chain last

If the generic chain appears first, it can swallow requests that were supposed to hit the API-specific or admin-specific chain.

That is the same category of bug people used to create with poorly ordered WebSecurityConfigurerAdapter classes.

Avoid overlapping request spaces casually

If two chains both plausibly match the same request, debugging gets messy fast. Keep the matchers intentional and mutually understandable.

For example, /api/** and /** is reasonable if ordered correctly. Two broad overlapping patterns that both appear "kind of specific" are much harder to reason about.

Security configuration should be explicit enough that a reader can predict which chain handles a given URL.

Legacy code may still show multiple adapters

If you are maintaining an older codebase, you may still see something like:

  • nested @Configuration classes
  • multiple WebSecurityConfigurerAdapter subclasses
  • '@Order annotations on those subclasses'

That was a legitimate older pattern, but new code should not be built around it. If you touch that area significantly, migrating to filter chains is usually worth it.

Keep shared concerns shared

When using multiple chains, it is easy to duplicate too much. Shared configuration such as password encoding, user details services, or common authentication providers should usually be defined once and injected where needed.

Separate filter chains should separate request policy, not explode the rest of the application into repeated security beans without reason.

Common Pitfalls

  • Copying WebSecurityConfigurerAdapter examples into a modern Spring Security codebase.
  • Putting a catch-all matcher before the more specific chains.
  • Creating overlapping request matchers that make chain selection ambiguous.
  • Duplicating all security beans per chain instead of sharing common infrastructure.
  • Migrating from adapters to filter chains mechanically without rethinking matcher boundaries.

Summary

  • Multiple WebSecurityConfigurerAdapter classes were an older way to apply different rules to different request groups.
  • The modern replacement is multiple ordered SecurityFilterChain beans.
  • Specific matchers should come before generic ones.
  • Clear request boundaries matter more than the number of security classes.
  • For new Spring Security code, use filter chains rather than building on the deprecated adapter pattern.

Course illustration
Course illustration

All Rights Reserved.