Misconfigurations that bite
Recognise the handful of mistakes behind most Spring Security bugs and security holes.
Open this lesson in the learning hubKey points
- A broad pattern above a narrow one wins silently.
/api/**before/api/admin/**means the admin rule never runs. - Spring fails fast if you add rules after
anyRequest(), but never warns about a shadowed pattern. Order by specificity. - Disabling CSRF on a cookie-authenticated app is a real vulnerability, not a convenience. Only token APIs may switch it off.
hasRole("ROLE_ADMIN")looks forROLE_ROLE_ADMIN. UsehasRole("ADMIN")instead.- Unexpected 403 on error pages? In Spring Security 6 authorization also runs on the ERROR dispatch — permit it explicitly.
- Never log raw passwords or tokens, and never return stack traces to clients. Both leak straight into log aggregators.
Example
// WRONG: the broad rule matches first, so the admin rule is dead code
http.authorizeHttpRequests(a -> a
.requestMatchers("/api/**").authenticated()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().denyAll());
// RIGHT: most specific first, error dispatch permitted, deny by default
http.authorizeHttpRequests(a -> a
.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers("/api/**").authenticated()
.anyRequest().denyAll());
Most Spring Security bugs are ordering, prefixes, or a CSRF switch flipped for the wrong reason.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Spring Security course, and every lesson in it is listed on the Spring Security contents page.