I have configured Spring Security (using Spring Boot 3.3.2) to follow the setup that is recommended for JavaScript Single Page Applications (We use React).
I managed to get my @WebMvcTest
tests working by using .with(csrf())
. The drawback of this is that it uses a request parameter and so it ends up on the output of my Spring Rest Docs generated documentation. For that reason, I want to use the CSRF token as a header.
If I use .with(csrf().asHeader())
, then the CSRF check fails. For some reason, the CsrfFilter
tries to compare a value like 8VkPR8LMFIbrsh2ld-qDcuA84ZnaLjk1AmaCL8CVhLdr6xxNyD87cPupJufGhC2SQce3QtANzKHiTw0YMVOxGvSnvIZe3yV4
with a UUID.
I have read at https://github.com/spring-projects/spring-security/issues/12774 that I can create an /csrf
endpoint like this:
@RestController
@RequestMapping("/csrf")
public class CsrfTokenRestController {
@GetMapping
public CsrfToken getCsrfToken(CsrfToken csrfToken) {
return csrfToken;
}
}
And then use something like this:
MvcResult mvcResult = this.mockMvc.perform(get("/csrf")).andReturn();
Cookie cookie = mvcResult.getResponse().getCookie("XSRF-TOKEN");
this.mockMvc.perform(post("/").header("X-XSRF-TOKEN", cookie.getValue()).cookie(cookie))
.andExpect(status().is2xxSuccessful())
However, in my case, there is no cookie in the response. So that does not work.
Is there anything else I can try to make this work?
Found the issue. I had multiple SecurityFilterChain beans and the one that is active for /csrf
did not have the csrf configuration like I had for my /api/**
endpoints. Adding that same config enabled the cookie and I could make it work.