Stop fighting Spring Security
Walk a request through the chain end to end and the framework stops being magic.
Spring Security is a chain of servlet filters wrapped around your application’s request pipeline. Every HTTP request the container receives walks through that chain before any controller method runs. The chain extracts credentials, verifies them, attaches the resulting identity to the request, and checks authorities against the URL or method being called.
Strip away the annotations and the DSL and that is the whole framework. An ordered stack of filters with named hooks for the parts that change between apps where users come from, how passwords are hashed, which credential formats you accept.
Why it matters
Most “why doesn’t my Spring Security config work” questions on Stack Overflow are not really questions about Spring Security. They are engineers trying to fix something without a mental model of what runs when. Once you can walk a request through the chain (filter order, where the principal lives, which provider gets called, which encoder verifies the password), the framework stops being a wall of annotations to copy-paste and starts being wiring you can configure on purpose.
The request pipeline
How an incoming HTTP request flows through Spring Security.
1. SecurityFilterChain
A bean wired into the servlet container that wraps each request in an ordered chain of filters. The request never goes straight to your controller. It walks through F1 → F2 → F3 → … → Fn first. Each filter has a single job, and their order is the whole game. Get the order wrong and you ship endpoints that look protected but are not.
2. SecurityContextHolder
A thread-local store that holds the current Authentication object for the duration of the request. Anything downstream (your service layer, @PreAuthorize, audit logging) calls SecurityContextHolder.getContext().getAuthentication() and gets the current user without re-authenticating. Spawn your own thread inside the request and the context does not follow; you propagate it explicitly.
3. AuthenticationFilter
Extracts credentials from the request and asks the AuthenticationManager to verify them. The credentials can come in as a Basic header, a form login post, or Authorization: Bearer ey7.... Different filter for each shape, same destination. Whatever comes back gets dropped into the SecurityContextHolder for the rest of the chain to use.
4. AuthorizationFilter
Runs after authentication and checks the user has the authorities the URL or method demands. Does ROLE_ADMIN cover /admin/**? If yes, the request continues. If no, AccessDeniedException stops it cold. Your controller never runs.
The auth machinery
How credentials get validated behind the scenes.
5. AuthenticationManager
An interface, but in practice it is a ProviderManager: a class that holds a list of AuthenticationProviders and asks each one in turn “can you verify this?” until one says yes. The list is how you mix authentication strategies in the same app: form login, JWT, LDAP, custom tokens, all sitting side by side as separate providers.
6. AuthenticationProvider
Validates a specific kind of credential. DaoAuthenticationProvider handles username and password by talking to UserDetailsService and PasswordEncoder. JwtAuthenticationProvider handles tokens by checking the signature. You write your own when you bolt on something the framework does not ship with.
7. UserDetailsService
Loads the user from your data store by username and returns a UserDetails object with the authorities attached. This is the boundary between Spring Security and your database. Implement it once, point it at your user table, and the rest of the framework consumes the result. The roles attached here are exactly what AuthorizationFilter checks against later.
8. PasswordEncoder
Hashes and verifies passwords. BCryptPasswordEncoder is the default. Raw password comes in, gets fed through the hash function, the result is compared against the stored $2a$... hash. Never compare raw passwords. The encoder bean has to match what generated the hashes already in your database, or every login fails with a confusing “bad credentials” even when the password is
correct.
SecurityFilterChain, SecurityContextHolder, AuthenticationFilter, AuthorizationFilter, AuthenticationManager, AuthenticationProvider, UserDetailsService, PasswordEncoder.
Walk a request through them once and Spring Security stops being a wall of annotations and starts being wiring you can reason about.




