skip to content

What does `apply(springSecurity())` do when building a MockMvc, and why is it needed before using postprocessors like `user(...)` or `csrf()`?

level: seniorimportance: must knowfreq 55%

answer

  1. springSecurity() = MockMvcConfigurer, apply() on builder
  2. wires FilterChainProxy (springSecurityFilterChain)
  3. enables .with(user()/csrf()/httpBasic()) postprocessors
  4. auto-applied under @AutoConfigureMockMvc
  5. builder-level vs request-level (apply vs with)

basics

~10 s

springSecurity() is a MockMvcConfigurer that wires Spring Security's filter chain into MockMvc. Without it, security filters don't run, so authentication/authorization and the csrf()/user() request postprocessors have no effect.

solid answer

~30 s

`SecurityMockMvcConfigurers.springSecurity()` returns a `MockMvcConfigurer` you attach to the builder via `.apply(springSecurity())`. It registers Spring Security's `springSecurityFilterChain` (`FilterChainProxy`) into the MockMvc filter pipeline and installs a `RequestPostProcessor` hook so security-aware postprocessors work. Without it, MockMvc sends requests straight to the DispatcherServlet with no security filters, so `@PreAuthorize`/`http.authorizeHttpRequests` are not enforced and helpers like `SecurityMockMvcRequestPostProcessors.user(...)`, `.csrf()`, `.httpBasic(...)` are ignored. Note the two layers: `apply(springSecurity())` configures the *builder*; the postprocessors are applied per-request with `.with(...)`. With Spring Boot's `@AutoConfigureMockMvc` (under `@SpringBootTest`), `springSecurity()` is auto-applied, so you mainly call it manually with `MockMvcBuilders.webAppContextSetup(context)` or `standaloneSetup`.

code

java · 19 lines
java
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;

@BeforeEach
void setUp(WebApplicationContext context) {
    // builder-level: turn Spring Security ON for this MockMvc
    this.mockMvc = MockMvcBuilders.webAppContextSetup(context)
                                  .apply(springSecurity())
                                  .build();
}

@Test
void adminCanCreate() throws Exception {
    mockMvc.perform(post("/api/orders")
                .with(user("alice").roles("ADMIN"))  // request-level postprocessor
                .with(csrf()))                          // needs springSecurity() active
           .andExpect(status().isCreated());
}

go deeper

for a junior

Know it turns Spring Security on in MockMvc so login/roles are enforced in tests.

for a middle

Distinguish apply(springSecurity()) (builder) from with(user()/csrf()) (per request) and know Boot auto-applies it.

for a senior

Explain the FilterChainProxy wiring, the postprocessor infrastructure it enables, and CSRF/403 gotchas.

for a principal

Decide test-slice strategy (webAppContextSetup vs @WebMvcTest vs standalone) so real security rules are actually exercised, not bypassed.

**The problem it solves.** MockMvc drives a real `DispatcherServlet` but does *not* automatically include arbitrary servlet filters. Spring Security enforces auth via a filter — the `FilterChainProxy` bean named `springSecurityFilterChain`. If that filter is not in MockMvc's chain, no security runs: endpoints behave as if unsecured, and the whole `spring-security-test` postprocessor machinery is inert. **What `springSecurity()` is.** `org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity()` returns a `MockMvcConfigurer`. A `MockMvcConfigurer` is a callback that customizes a `ConfigurableMockMvcBuilder` before `build()`. You attach it with `.apply(...)`. Its job: 1. Insert the `springSecurityFilterChain` (`FilterChainProxy`) as a filter in the MockMvc filter chain, so real security filters (authentication, authorization, CSRF, etc.) execute on every simulated request. 2. Register a `RequestPostProcessor` support hook (a `TestSecurityContextHolderPostProcessor` / SecurityContext plumbing) so that per-request postprocessors from `SecurityMockMvcRequestPostProcessors` can seed a `SecurityContext`, add CSRF tokens, set Basic auth headers, etc. There is an overload `springSecurity(Filter springSecurityFilterChain)` for supplying the filter explicitly when it is not resolvable from the context by name. **Two distinct layers — do not conflate them.** - **Builder-level (once):** `.apply(springSecurity())` on `MockMvcBuilders.webAppContextSetup(context)` (or `standaloneSetup(...)`). This turns security *on* for the MockMvc instance. - **Request-level (per call):** `.with(...)` using `SecurityMockMvcRequestPostProcessors` — e.g. `.with(user("alice").roles("ADMIN"))`, `.with(csrf())`, `.with(httpBasic("u","p"))`, `.with(jwt())`, `.with(anonymous())`. These are `RequestPostProcessor`s that mutate the `MockHttpServletRequest` before it enters the filter chain. They only take effect because `springSecurity()` wired the supporting infrastructure. **Boot auto-configuration.** Under `@SpringBootTest` + `@AutoConfigureMockMvc`, Boot's `MockMvcSecurityConfigurer` applies `springSecurity()` for you, so the injected `MockMvc` already has security wired. You typically call `apply(springSecurity())` yourself only when building MockMvc manually via `webAppContextSetup`/`standaloneSetup`, or in a slice like `@WebMvcTest` where you build it explicitly. **Common gotchas.** - Using `.with(user(...))` but forgetting `apply(springSecurity())` on a manually built MockMvc → the user is never authenticated; requests appear anonymous and you get unexpected 401/403 or, conversely, endpoints seem open. - A POST/PUT returning 403 in a secured app usually means a missing CSRF token → add `.with(csrf())` (which requires springSecurity() to be active). - `standaloneSetup` builds a minimal MVC without your `SecurityFilterChain` bean; `springSecurity()` there won't magically pull your app's security config — prefer `webAppContextSetup`/`@WebMvcTest` when you need real security rules. - `springSecurity()` must be applied *before* `build()`; applying it after has no effect. **Related import.** `import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;` and `import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;`.

  • Your POST test returns 403 even with `.with(user(...))`. What is the likely cause?
    A missing CSRF token. Spring Security enforces CSRF on state-changing methods; add `.with(csrf())`. This only works if `apply(springSecurity())` (or Boot auto-config) wired the security filter chain.
  • Do you always need to call `apply(springSecurity())` explicitly?
    No. Under @SpringBootTest with @AutoConfigureMockMvc, Boot applies it automatically. You call it yourself when building MockMvc manually via webAppContextSetup/standaloneSetup or configuring @WebMvcTest explicitly.
  • What is the difference between `.apply(springSecurity())` and `.with(user(...))`?
    apply() is a builder-level MockMvcConfigurer that installs the security filter chain once. with() applies a per-request RequestPostProcessor that seeds the SecurityContext/CSRF for a single request. The latter needs the former to be effective.

saying these in an interview costs you the question

  • Claiming springSecurity() is a RequestPostProcessor applied with .with() (it is a MockMvcConfigurer applied with .apply())
  • Thinking user()/csrf() work without the security filter chain wired
  • Believing standaloneSetup + springSecurity() enforces your app's real security rules
  • Assuming you must always call it even under @AutoConfigureMockMvc

context