I am trying to use Spring Boots suggested SpaCsrfTokenRequestHandler that will use the double submit cookie pattern for CSRF but the MockMvc api with csrf() does not seem to support this when it comes to testing. Manually supplying a csrf token value in the cookie and header on request works but ideally the MockMvc api would work with the csrf() option.
I am following spring docs here: Spring Boot CSRF With SPA Application Spring Boot Testing With CSRF
With the SPA App, a double submit cookie is used as the CSRF protection mechanism, where the JS app should return the value held in an "xsrf-token" cookie and pass it in an "x-xsrf-token" header per request.
Generally the approach here: Double Submit Cookie Pattern
When I use Spring Security in tests as shown below using the MockMvc with(csrf().asHeader())
the token always is said to be invalid.
I am unsure if that is because mockmvc is not binding a value to a header AND a cookie or if this API is not useable for this scenario?
This works:
mockMvc
.perform(post("/api/some-endpoint")
.cookie(new Cookie("xsrf-token","abc"))
.header("x-xsrf-token","abc")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content("Some body content")
.andExpect(status().is2xxSuccessful())
.andReturn();
This does not:
org.springframework.security.web.csrf.InvalidCsrfTokenException: Invalid CSRF Token 'J68ItVNNwwdMhD-qLrdkGN8ox2fAk73IO4md1BNIGvIl-IFlQZY8hGp59GRhtAbOG5pQKe0Z6galoInlX-z-7XJxfsoVy7AD' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
mockMvc
.perform(post("/api/some-endpoint")
.cookie(new Cookie("xsrf-token","abc"))
.with(csrf().asHeader())
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content("Some body content")
.andExpect(status().is2xxSuccessful())
.andReturn();
And nor does this:
org.springframework.security.web.csrf.InvalidCsrfTokenException: Invalid CSRF Token '1SKNwUSrMfPyT9Wp4A1hP8zjY-31exqNdqGvz4avElN50TTQthDp8HOcAZDffu2cgSBVC__UTtTCQnigEJmcquTKczdLtwHg' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.
mockMvc
.perform(post("/api/some-endpoint")
.with(csrf().asHeader())
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content("Some body content")
.andExpect(status().is2xxSuccessful())
.andReturn();