What does `apply(springSecurity())` do when building a MockMvc, and why is it needed before using postprocessors like `user(...)` or `csrf()`?
answer
- springSecurity() = MockMvcConfigurer, apply() on builder
- wires FilterChainProxy (springSecurityFilterChain)
- enables .with(user()/csrf()/httpBasic()) postprocessors
- auto-applied under @AutoConfigureMockMvc
- builder-level vs request-level (apply vs with)
basics
~10 sspringSecurity() 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 linesimport 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
Know it turns Spring Security on in MockMvc so login/roles are enforced in tests.
Distinguish apply(springSecurity()) (builder) from with(user()/csrf()) (per request) and know Boot auto-applies it.
Explain the FilterChainProxy wiring, the postprocessor infrastructure it enables, and CSRF/403 gotchas.
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