The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
A 403 from a Spring Boot MockMvc test can mean a missing CSRF token, an authenticated user without the required permission, or a security rule that the test has not loaded as expected. For a POST, PUT, PATCH, or DELETE, start by adding .with(csrf()). If the request still fails, check the test user’s exact role or authority and confirm that MockMvc is running the application’s Spring Security filter chain.
Try the smallest likely fix
Spring Security protects unsafe HTTP methods against cross-site request forgery (CSRF) by default, unless the application changes that configuration. A MockMvc request does not automatically include a valid CSRF token. Add one with Spring Security’s test request post-processor:
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
mockMvc.perform(post("/users").with(csrf()))
.andExpect(status().isCreated());
If the endpoint also requires an authenticated user, supply that user as well:
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchimport static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
mockMvc.perform(post("/api/orders")
.with(user("alice").roles("USER"))
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"productId": 42}
"""))
.andExpect(status().isOk());
These address different checks: the CSRF token satisfies CSRF protection; the user post-processor supplies an authenticated principal. Neither automatically grants a role that the endpoint requires. See the Spring Security CSRF reference and its MockMvc test support documentation.
What a 403 tells you—and what it does not
HTTP 403 means access was denied, but it does not identify the reason. In Spring Security, common causes include:
- CSRF rejection: an unsafe request has no valid token.
- Authorization denial: the user is authenticated but lacks the role or authority required by a URL rule.
- Method-security denial: a method-level rule, such as
@PreAuthorize, rejects the user. - Application-specific denial: a custom filter, access-denied handler, or application check blocks the request.
An unauthenticated request does not always produce 403. Depending on the application’s configuration, it may instead return 401, redirect to a login page, or be handled another way. Diagnose the response in the context of the endpoint and the security configuration rather than treating every 403 as “not logged in.”
Add a CSRF token to unsafe requests
For a form-style test, .with(csrf()) supplies a valid token as a request parameter. If the application expects the token in a header, use:
Free tools Windows power users keep installed
One-click scans. No signup required.
mockMvc.perform(post("/submit")
.with(csrf().asHeader()))
.andExpect(status().isOk());
Apply CSRF where it belongs: typically to POST, PUT, PATCH, and DELETE requests when the configured application requires it. A GET should normally not need a CSRF token. Spring Security’s behavior can be customized, so follow the application’s actual configuration.
You can also test that the protection rejects missing or invalid tokens. These tests are useful when CSRF behavior itself is part of what you need to verify:
Rank #2
mockMvc.perform(post("/submit"))
.andExpect(status().isForbidden());
mockMvc.perform(post("/submit")
.with(csrf().useInvalidToken()))
.andExpect(status().isForbidden());
For the documented token post-processors and CSRF behavior, consult the Spring Security CSRF documentation.
Supply the right test user and permissions
Use @WithMockUser when a test method or class should run as a consistent user:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problems@Test
@WithMockUser(username = "alice", roles = "USER")
void userCanCreateOrder() throws Exception {
mockMvc.perform(post("/orders").with(csrf()))
.andExpect(status().isCreated());
}
For a single request, use user():
mockMvc.perform(get("/admin")
.with(user("alice").roles("ADMIN")))
.andExpect(status().isOk());
Match the test permissions to the authorization rule. In the usual Spring Security role convention, hasRole("ADMIN") checks for an authority named ROLE_ADMIN. The test helper’s roles("ADMIN") adds that prefix for you; pass the role name without ROLE_. By contrast, hasAuthority("REPORT_READ") checks for that exact authority, so supply it explicitly:
mockMvc.perform(get("/reports")
.with(user("alice")
.authorities(new SimpleGrantedAuthority("REPORT_READ"))))
.andExpect(status().isOk());
For example, .roles("ADMIN") and .authorities("ADMIN") are not interchangeable: the former normally produces ROLE_ADMIN, while the latter represents the exact authority ADMIN. Custom role-prefix configuration can change the conventional mapping, so check the application’s setup if its rules differ.
For an authority such as an OAuth2 scope, provide the exact string the rule requires, for example SCOPE_orders.write. A mock user may not reproduce an application’s custom authentication type, JWT claims, or principal object. If authorization depends on those details, build a test authentication that represents them using the appropriate Spring Security test support.
Rank #3
Ensure MockMvc includes Spring Security
With Spring Boot’s auto-configured MockMvc, a full-context test commonly looks like this:
Recommended Free Tools
@SpringBootTest
@AutoConfigureMockMvc
class OrderControllerSecurityTest {
@Autowired
MockMvc mockMvc;
}
If you build MockMvc yourself from a web application context, apply Spring Security’s MockMvc configurer:
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
@BeforeEach
void setUp(WebApplicationContext context) {
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
This manual integration adds the security filter chain and the test security-context support needed for features such as @WithMockUser. Boot-managed MockMvc ordinarily configures the corresponding integration for you; do not add manual setup blindly on top of it. The documented manual setup is described in the Spring Security MockMvc setup guide.
Security-specific test helpers such as csrf(), user(), and @WithMockUser come from spring-security-test. If those APIs cannot be resolved, check that the test dependency is present. Let Spring Boot’s dependency management or the Spring Security BOM manage the version when your project uses one.
<!-- Maven -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
// Gradle
testImplementation 'org.springframework.security:spring-security-test'
For project testing infrastructure, see the Spring Boot testing reference and the Spring Security testing reference.
When @WebMvcTest returns 403
@WebMvcTest loads a web slice rather than the entire application. When Spring Security is on the classpath, current Spring Boot documentation says the slice auto-configures Spring Security and MockMvc when applicable. A test can therefore encounter security even though it loads only a controller and related MVC components.
@WebMvcTest(OrderController.class)
class OrderControllerTest {
@Autowired
MockMvc mockMvc;
@Test
@WithMockUser(roles = "USER")
void createsOrder() throws Exception {
mockMvc.perform(post("/orders").with(csrf()))
.andExpect(status().isCreated());
}
}
If the slice does not include the security configuration that defines the rules you intend to test, import it explicitly:
@WebMvcTest(OrderController.class)
@Import(SecurityConfig.class)
class OrderControllerTest {
}
If that configuration pulls in unrelated infrastructure, separate security configuration from those dependencies or use a full application context. Also provide the controller’s mocked collaborators as needed; a missing service mock is a separate test setup problem, not a reason to remove security. See Spring Boot’s testing how-to and the @WebMvcTest API documentation. Boot package locations and test APIs can vary across major versions; use documentation matching your project’s Boot and Security versions.
Standalone MockMvc is not a full security test
A setup such as MockMvcBuilders.standaloneSetup(controller).build() does not load the application context. Do not assume it includes your configured Spring Security filter chain. If the purpose is to test security behavior, prefer a context-backed @WebMvcTest or @SpringBootTest. If standalone setup is intentional, register the relevant security filter explicitly and configure the test to match the application. Otherwise, a passing standalone controller test says nothing about the production security chain.
Trace a 403 that remains after adding CSRF
Use a small set of tests to separate token failure from authorization failure:
Best Value
@Test
void missingCsrfIsForbidden() throws Exception {
mockMvc.perform(post("/orders")
.with(user("alice").roles("USER")))
.andExpect(status().isForbidden());
}
@Test
void userWithCsrfCanCreateOrder() throws Exception {
mockMvc.perform(post("/orders")
.with(user("alice").roles("USER"))
.with(csrf()))
.andExpect(status().isCreated());
}
@Test
void wrongRoleIsForbiddenEvenWithCsrf() throws Exception {
mockMvc.perform(post("/admin/orders")
.with(user("alice").roles("USER"))
.with(csrf()))
.andExpect(status().isForbidden());
}
The endpoint paths and expected success statuses are examples; use the rules and responses defined by your application. If the request still fails, investigate in this order:
- Check the method. For an unsafe method, confirm the configured CSRF protection is satisfied.
- Check authentication. Supply a user if the endpoint is protected.
- Match permissions exactly. Compare the rule’s
hasRole,hasAuthority, or related expression with the user’s granted authorities. - Check the route and matcher. Confirm the request path and method actually match the rule you think applies.
- Check method security. A URL rule may permit the request while
@PreAuthorizeor another method-level check denies it. - Check what the test loaded. Verify the intended
SecurityFilterChain, security configuration, and custom filters are present. - Inspect evidence. Review the response body and headers, test logs, and any custom
AccessDeniedHandler; custom handling can obscure the original reason.
A GET that returns 403 points away from the usual missing-CSRF explanation. Focus instead on authorization, method security, custom filters, request matchers, or customized CSRF behavior. If @WithMockUser has no effect, check for spring-security-test and verify that your MockMvc setup installs Spring Security’s test integration. If only standalone setup fails, the missing filter chain is a likely explanation.
Do not disable CSRF just to make the test pass
Disabling CSRF in application configuration can make a test pass by removing the protection being tested. Prefer .with(csrf()) when the endpoint is meant to remain CSRF-protected.
Disabling CSRF or excluding selected request matchers can be appropriate when it reflects a deliberate production security model. That is an application-security decision, not a generic MockMvc workaround; “stateless API” alone is not a complete threat-model decision. For an intentional, narrowly scoped exception, Spring Security supports ignored request matchers, for example:
http.csrf(csrf -> csrf
.ignoringRequestMatchers("/api/webhooks/**"));
Use the configuration style and matcher appropriate to the Spring Security version in your application, and make sure the exception is justified for those endpoints. Ignoring CSRF changes which requests are protected; adding .with(csrf()) changes only what the test sends.
Spring Security’s core MockMvc remedies are established across multiple major versions, but Boot’s annotations, package locations, and configuration APIs evolve. When adapting snippets, consult documentation for the versions used by your project. Relevant references: CSRF protection, Spring Security MockMvc tests, and Spring Boot application testing.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

