Join our Newsletter — 33% off our NHI Course
Home› Guides› Spring Security Configuration Guide: Filter Chains, Method Security,…
Guide Application Security

Spring Security Configuration Guide: Filter Chains, Method Security, OAuth2 Resource Server and CSRF

PDF for newsletter subscribers · free to read online

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 27 October 2026 12 min read
On this page

Most access control bugs in Spring applications are not flaws in Spring Security but configuration mistakes: a filter chain that never matches, a permitAll() rule placed above a stricter one, a controller method nobody annotated, or CSRF switched off to make a test pass. Spring Security is the default security framework for enterprise Java, and its behaviour is precise but unforgiving: chains and rules are evaluated in order and only the first match applies. This guide is a configuration reference for engineers and reviewers working with Spring Security 6.x and 7.x on servlet (Spring MVC) and reactive (WebFlux) stacks. It covers how filter chains and authorisation decisions work, method security, OAuth2 resource server settings including audience validation and DPoP, CSRF, logging and a hardening baseline. Language-level Java risks are covered in the Java and Spring Security Guide; this page goes deeper on the framework itself.

Key takeaways

  • First match wins, twice. FilterChainProxy invokes only the first SecurityFilterChain whose matcher fits the request, and AuthorizationFilter applies only the first matching rule inside it; order is security policy.
  • Deny by default. End every chain with anyRequest().denyAll() or anyRequest().authenticated(), and add one catch-all chain with no securityMatcher as the last bean.
  • Unannotated methods are unsecured. Method security with @PreAuthorize protects only what is annotated and called through the Spring proxy, so keep request-level rules as the backstop.
  • Resource servers must check audience. issuer-uri validates iss, exp and nbf, but not aud; set audiences or a custom validator, and consider DPoP for high-value APIs.
  • Keep CSRF on for browser sessions. Disable it only for stateless APIs that do not use cookies for authentication, and prefer ignoringRequestMatchers for specific endpoints.

How identity and access work in Spring Security

Servlet filter chains

Spring Security plugs into the servlet container through DelegatingFilterProxy, which hands requests to the FilterChainProxy bean. FilterChainProxy applies the HttpFirewall and then selects a SecurityFilterChain. The reference documentation is explicit that only the first chain that matches is invoked: if /api/** is matched by the first chain, a later chain that also matches is never consulted. Chain priority is set with @Order on each SecurityFilterChain bean, and a bean without @Order is considered last.

Within a chain, filters run in a fixed order: CsrfFilter, then authentication filters, then AuthorizationFilter, which is last by default. You can print the filter list for a request to confirm what is actually running.

Authorisation rules

  • Default: with Spring Boot and no custom chain, every request must be authenticated.
  • Ordering: authorizeHttpRequests rules are processed in the order listed and only the first match applies. Put specific rules first and the catch-all last.
  • Matchers: Ant-style path patterns by default, with RegexRequestMatcher available; anchor regular expressions and test them.
  • Dispatch types: authorisation applies to FORWARD, ERROR and INCLUDE dispatches as well as the original request, so error pages and view forwards may need explicit rules; permit those dispatcher types deliberately rather than broadening path rules.
  • Firewall: the default StrictHttpFirewall rejects un-normalised requests and strips path parameters and duplicate slashes for matching. Relaxing it to allow matrix variables or encoded characters should be a reviewed decision.

Servlet versus reactive

ConcernServlet (Spring MVC)Reactive (WebFlux)
Enable@EnableWebSecurity@EnableWebFluxSecurity
Chain typeSecurityFilterChain built from HttpSecuritySecurityWebFilterChain built from ServerHttpSecurity
Request rulesauthorizeHttpRequests with requestMatchersauthorizeExchange with pathMatchers
Method security@EnableMethodSecurity@EnableReactiveMethodSecurity; methods return Mono or Flux
Security contextThread-bound SecurityContextHolderReactor context; thread-local lookups do not work
FirewallStrictHttpFirewallStrictServerWebExchangeFirewall

Mixing the two models (for example calling servlet-style SecurityContextHolder in WebFlux code) is a common source of "anonymous" principals in production.

Admin roles and privileged access

Spring Security has no admin console: privileged access is whatever your rules grant to administrative authorities and management endpoints.

  • Authorities over roles in expressions: hasRole('ADMIN') checks for ROLE_ADMIN; hasAuthority checks the exact string. The method security documentation advises favouring granted authorities over complicated SpEL expressions, which are hard to review.
  • Separate admin chain: put admin paths in their own SecurityFilterChain with @Order ahead of the general chain, stronger authentication (for example MFA at the identity provider) and a denyAll() catch-all.
  • Method security for business operations: enable @EnableMethodSecurity, which activates @PreAuthorize, @PostAuthorize, @PreFilter and @PostFilter. @Secured is legacy; @PreAuthorize is recommended. Use @PostAuthorize("returnObject.owner == authentication.name") style checks for object-level ownership, or @AuthorizeReturnObject to secure returned domain objects.
  • Proxy limits: method security is built on Spring AOP, so calls from one method to another inside the same bean bypass the proxy and its checks. Put the annotation on the entry point or move the call to another bean.
  • Management endpoints: Actuator endpoints need their own chain restricted to an operations authority or a separate management port. See the Spring Boot Actuator and Management Endpoint Security Guide.
  • Migration: replace @EnableGlobalMethodSecurity with @EnableMethodSecurity; the reference has a migration section.
Request-level rulesMethod-level rules
Coarse-grained, declared in one configuration class (DSL)Fine-grained, declared on each method (annotations and SpEL)
Cover every request, including endpoints nobody rememberedCover only annotated methods reached through the proxy
Best for authentication requirements, admin areas, deny-by-defaultBest for ownership and business permission checks

The reference warns that with annotation-based method security, unannotated methods are not secured, and recommends a catch-all request rule to protect against that. Use both layers.

Integrations, API tokens and service accounts

OAuth2 resource server (JWT)

  • Issuer: spring.security.oauth2.resourceserver.jwt.issuer-uri must equal the iss claim and point at a discovery document; the resource server then validates exp, nbf and iss. Supplying jwk-set-uri as well lets the server start without contacting the issuer while still validating iss.
  • Audience: set spring.security.oauth2.resourceserver.jwt.audiences (or add an audience validator) so tokens minted for another API are rejected. OWASP ASVS 5.0 V10.3.1 requires resource servers to accept only tokens intended for them.
  • Scopes and authorities: scopes become authorities with the SCOPE_ prefix by default; use access(hasScope("message:read")) or hasAuthority("SCOPE_message:read"), and a custom JwtAuthenticationConverter if roles come from another claim.
  • Sender-constrained tokens: the resource server reference documents DPoP-bound access tokens (RFC 9449): the client sends Authorization: DPoP <token> with a DPoP proof header, and the server checks that the key thumbprint in the token's cnf.jkt claim matches the proof key and that the proof's ath claim matches the token hash. ASVS V10.3.5 (Level 3) calls for sender-constrained tokens. See the DPoP Guide.
  • Opaque tokens: introspection clients authenticate to the authorisation server with a client secret or key; store that credential in a secrets manager, not application.yml.

Service accounts and outbound calls

  • Machine clients: services calling other APIs should use the OAuth2 client support with the client credentials grant and short-lived tokens, not shared API keys in headers. See the Machine-to-Machine OAuth (Client Credentials) Guide.
  • Separate chains for machine APIs: give machine-to-machine endpoints their own stateless chain that accepts only bearer or DPoP tokens and no form login or sessions.
  • Client secrets: prefer private_key_jwt or mTLS client authentication over shared secrets where the authorisation server supports them, and keep keys out of source control.

CSRF

  • Default: CSRF protection is on for unsafe methods such as POST. Tokens are stored in the HttpSession by HttpSessionCsrfTokenRepository; since Spring Security 6 token loading is deferred and each token is randomised per request to resist BREACH.
  • Single-page applications: CookieCsrfTokenRepository writes an XSRF-TOKEN cookie and reads X-XSRF-TOKEN; use withHttpOnlyFalse() only when JavaScript must read the cookie, as the reference recommends. Spring Security 6 changed SPA handling, so follow the SPA section rather than old examples.
  • Narrow exceptions: before disabling CSRF, the reference suggests ignoring only specific endpoints with ignoringRequestMatchers, for example a webhook authenticated by signature.
  • When disabling is correct: stateless APIs that authenticate every request with a bearer or DPoP token, and never with cookies, do not need CSRF tokens. See the CSRF Prevention Guide.

Decision guidance

  • Session login or token resource server: server-rendered applications suit form or OIDC login with sessions and CSRF; APIs consumed by other services or SPAs through a backend suit stateless resource server chains. Many applications need both, in separate chains.
  • Bearer or DPoP: bearer tokens are simpler and fine for internal low-risk APIs with short lifetimes; DPoP is worth the client work for payment, admin and partner APIs where token theft is a realistic threat.
  • Small teams: one browser chain, one API chain, deny-by-default and audience validation cover most risk. Large estates should publish a shared configuration library with these defaults and a test kit, so each service does not reinvent ordering.

Logging and detection

  • Authentication events: register a DefaultAuthenticationEventPublisher and listen for AuthenticationSuccessEvent and AuthenticationFailureEvent subclasses; forward them to your SIEM with principal, client IP and outcome.
  • Authorisation events: publish AuthorizationDeniedEvent with SpringAuthorizationEventPublisher; AuthorizationGrantedEvent is optional and noisy, so enable it only for sensitive operations.
  • Firewall rejections: log RequestRejectedException from the HTTP firewall; spikes indicate path traversal or matcher bypass probing.
  • Token validation failures: log JWT rejections by reason (issuer, audience, expiry, signature) without logging the token. See the JWT and Session Tokens in Code and Logs Guide.
  • Debug output: security debug and TRACE logging print filter chains and request details; never leave them on in production.

Metrics:

  • Authorisation denials per endpoint per day, with alerts on sudden changes.
  • Percentage of controller endpoints covered by an explicit request rule or method annotation (from a build-time test).
  • JWT rejections for wrong audience, a sign of token misuse across services.
  • Authentication failures per account and per source address.
  • Number of chains or rules containing permitAll(), reviewed each release.

Hardening baseline

AreaSettingCheck
Chain orderingSpecific chains with securityMatcher and @Order; one final catch-all chainTest that unknown paths are denied
Rule orderingSpecific requestMatchers first; anyRequest().denyAll() or authenticated() lastUnit tests with MockMvc for each role and an anonymous user
Method security@EnableMethodSecurity, @PreAuthorize on service entry pointsArchitecture test that service methods carry an annotation
FirewallDefault StrictHttpFirewallReview any relaxations
Resource serverissuer-uri plus audiences; DPoP for high-value APIsReject a valid token minted for another audience
SessionsStateless (SessionCreationPolicy.STATELESS) for token APIs; session fixation protection left on for browser appsNo JSESSIONID issued on API chains
CSRFOn for cookie-authenticated apps; narrow ignores onlyPOST without token is rejected
HeadersDefaults kept: Cache-Control: no-cache, no-store, max-age=0, must-revalidate, X-Content-Type-Options: nosniff, HSTS max-age=31536000 ; includeSubDomains on HTTPS, X-Frame-Options: DENY, X-XSS-Protection: 0; add a CSPResponse header scan. See the Security Headers Guide.
PasswordsDelegatingPasswordEncoder with a modern adaptive algorithmNo NoOpPasswordEncoder anywhere
Static resourcesUse permitAll() rules rather than removing paths from Spring Security, so headers still applyHeaders present on static responses

Rollout and testing

  1. Print the filter chains for representative URLs and draw the chain map: which chain handles which paths.
  2. Write MockMvc or WebTestClient tests for every endpoint and role, including anonymous access and wrong-audience tokens, before changing rules.
  3. Refactor to deny-by-default in a feature branch; run the test suite and a dynamic scan against a staging environment.
  4. Release behind a canary instance and watch authorisation denial metrics; rollback is redeploying the previous configuration, so keep security config changes in their own commits.
  5. Add the tests to CI so a new controller without a rule fails the build.

Framework mapping

FrameworkReferenceSpring Security control
OWASP ASVS 5.0V8.2.1, V10.3.1, V10.3.5, V3.5.1Function-level access, audience validation, sender-constrained tokens, CSRF defences
NIST SP 800-53 Rev. 5AC-3, AC-6, IA-2, SC-23, AU-2Access enforcement, least privilege, authentication, session authenticity, event logging
NIST CSF 2.0PR.AA-05Access permissions defined, enforced and reviewed
MITRE ATT&CKT1078 Valid AccountsStrong authentication and audience checks limit reuse of stolen credentials and tokens

Common misconfigurations

  • Broad permitAll() above specific rules: requestMatchers("/api/**").permitAll() listed before requestMatchers("/api/admin/**").hasRole("ADMIN") makes the admin rule unreachable.
  • Chain that never matches: two chains without distinct securityMatcher values, or a general chain ordered first, so the stricter API chain is never used.
  • No catch-all: rules list known endpoints and stop, so new endpoints are reachable by any authenticated or anonymous user depending on defaults.
  • Method security assumed everywhere: missing annotations, or internal calls that bypass the proxy, leave business operations unprotected. See the Broken Access Control Prevention Guide.
  • No audience validation: any token from the shared identity provider works on every API, so one compromised low-value client opens all services.
  • CSRF disabled globally on a session-based app: copied from an API tutorial, it reopens cross-site request forgery on every form.
  • Error and forward dispatches overlooked: broad permits added to fix error page access instead of permitting the ERROR dispatcher type.

Practitioner checklist

  • Map every SecurityFilterChain, its securityMatcher and @Order, and keep one final catch-all chain.
  • Order rules from specific to general and end each chain with denyAll() or authenticated().
  • Enable @EnableMethodSecurity and put @PreAuthorize on service entry points, keeping request rules as the backstop.
  • Configure resource servers with issuer-uri and audiences, map scopes deliberately, and use DPoP for high-value APIs.
  • Keep CSRF enabled for cookie-based sessions and use ignoringRequestMatchers for narrow exceptions.
  • Keep the default StrictHttpFirewall and security headers, and add CSP.
  • Isolate Actuator and admin paths in their own chains with an operations authority.
  • Publish authentication and authorisation denied events to the SIEM.
  • Test every endpoint for anonymous, wrong-role and wrong-audience access in CI.

Standards and references

Related NHI Mgmt Group resources: Java and Spring Security Guide · Spring Boot Actuator and Management Endpoint Security Guide · Broken Access Control Prevention Guide · DPoP Guide · JWT Security Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 27 October 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.