← Spring Boot®: applications, contracts and operations
07 / 10 · 60 MIN

Security and authorization boundaries

Define security coverage for each request, separate authentication from authorization, and diagnose rejection without removing controls.

The chain defines coverage

SecurityFilterChain is selected by a matcher. If the priority chain uses securityMatcher("/api/**"), it only receives that set of requests. Its anyRequest covers what entered that chain, not every application URL. An /exports controller can remain outside it.

With several chains, priority and matching determine selection. A final chain without a path restriction can establish a fallback policy. If no chain matches, Spring Security does not protect the request; absence of a rule is not equivalent to denyAll.

The first match decides

Within a chain, authorization rules are evaluated in declaration order. If /reports/** accepts any authenticated user before /reports/admin/** requires ADMIN, an administrative request first encounters the broad rule. The specificity of the second path does not automatically promote it.

Place restrictive conditions before broad ones and explicitly decide residual behavior. Include the HTTP method: reading a report and publishing it can require distinct authorities. The matrix should contain both legitimate access and attempts without the required authority.

Authorities and service boundaries

hasAuthority compares the specified authority. With the default prefix, hasRole("ADMIN") looks for ROLE_ADMIN. A username of admin does not replace that authority. The authentication contract should explain how the principal receives authorities and who controls that assignment.

EnableMethodSecurity activates annotations such as PreAuthorize on managed-bean methods; adding the starter is insufficient. A service boundary can need decisions about parameters and specific objects. A general HTTP read rule does not itself establish that the user can read every report identified by id.

Separate CSRF from authority

A POST can be rejected before the controller because its CSRF token is missing, even when the session is authenticated and holds REPORT_WRITE. Protection covers unsafe methods by default. The received token must be resolved and compared with the value expected by the configured mechanism.

To analyze authority, use a request satisfying CSRF. To analyze CSRF, retain sufficient identity and authority while varying the token. Do not turn a state change into GET to avoid checking. Protection policy should follow the authentication and client model, not an isolated 403.

Verify stored credentials

PasswordEncoder represents a one-way transformation for storing and checking passwords. matches receives the presented secret and stored encoded value. Recovering an original password from that value is neither necessary nor appropriate.

DelegatingPasswordEncoder uses the {id}encodedPassword format to select an implementation. Without a recognized id and without a configured fallback encoder, comparison can throw IllegalArgumentException. Identify the historical algorithm before migration; adding a bcrypt label to bytes in another format does not convert them.

Validate a token’s destination

In a JWT resource server, reading the payload does not establish trust. Validation includes signature and time conditions; issuer configuration must check iss. A valid signature from the expected issuer can still belong to a token intended for another resource.

When the API requires an audience, configure Boot audiences or an equivalent validator while retaining other validators. After validation, authorities still determine access. An accepted token does not replace object authorization or establish that a write operation actually committed.

Guided policy reading

The example has one chain without a restrictive securityMatcher. GET /public/status is permitted by HTTP policy; GET /reports/42 requires REPORT_READ and POST /reports/42 requires REPORT_WRITE. Other methods and paths reach denyAll. Rules do not create controllers or supply an authentication provider.

The example retains CSRF and uses HTTP Basic for authentication; a real deployment needs protected transport and its own credential configuration. In assessment, interpret requests and stated conditions. Do not execute code or infer object authorization from these path rules.

// SecurityConfiguration.java in package com.acme.reports.
// Servlet MVC with Spring Security. A compatible authentication provider is
// configured separately; no credentials are defined in this teaching excerpt.
package com.acme.reports;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration(proxyBeanMethods = false)
@EnableMethodSecurity
public class SecurityConfiguration {
  @Bean
  SecurityFilterChain reportsSecurity(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(rules -> rules
        .requestMatchers(HttpMethod.GET, "/public/status").permitAll()
        .requestMatchers(HttpMethod.GET, "/reports/**").hasAuthority("REPORT_READ")
        .requestMatchers(HttpMethod.POST, "/reports/**").hasAuthority("REPORT_WRITE")
        .anyRequest().denyAll());
    http.httpBasic(Customizer.withDefaults());
    // CSRF protection remains enabled. No restrictive securityMatcher.
    return http.build();
  }
}
IN PRACTICE

Read three requests: GET reports with REPORT_READ, POST with that same authority, and POST with REPORT_WRITE. To isolate authority on POST, assume a valid CSRF token. The first can be authorized, the second is rejected, and the third satisfies the authority rule. The handler and remaining controls must still permit the operation.

Common pitfalls

Putting broad rules first; confusing hasRole with hasAuthority; leaving URLs outside every chain; treating authentication as CSRF proof; accepting JWTs merely because claims can be read.

Related topics: Test scope and integration evidence · HTTP routing and request contracts · Health, observability and diagnosis

Take this idea with you

An access decision needs coverage, valid identity and appropriate authorization. Record which control made the decision and preserve the others when fixing failure.

Create account

Reference: Authorize HTTP requests · Spring Boot 4.1.1 / Spring Framework 7.0.9 / Java 25