Testing a secured endpoint

Spring Security · lesson 20 of 31 · 4 min read

Make MockMvc run the real filter chain, then drive it with mock users, JWTs and CSRF tokens.

Open this lesson in the learning hub

Key points

  • A plain standaloneSetup MockMvc has no security filters, so the test passes and proves nothing.
  • Boot applies springSecurity() for you in @WebMvcTest. Build MockMvc by hand and you must call it yourself.
  • @WithMockUser(roles = "ADMIN") puts an authenticated user in the context before the request runs.
  • A resource server needs a token, not a user: add .with(jwt().authorities(...)) from the test post-processors.
  • CSRF is on for cookie apps, so a POST needs .with(csrf()) or it fails with 403 for the wrong reason.
  • Assert the negative cases too. A happy-path-only test never notices a rule that quietly stopped working.

Example

@WebMvcTest(PostController.class)
class PostControllerSecurityTest {

    @Autowired MockMvc mvc;

    @Test
    void anonymousIsRejected() throws Exception {
        mvc.perform(post("/api/posts")).andExpect(status().isUnauthorized());
    }

    @Test
    @WithMockUser(roles = "USER")
    void plainUserIsForbidden() throws Exception {
        mvc.perform(post("/api/posts").with(csrf()))
           .andExpect(status().isForbidden());
    }

    @Test
    void tokenWithTheRightScopeWins() throws Exception {
        mvc.perform(post("/api/posts").with(csrf())
                .with(jwt().authorities(new SimpleGrantedAuthority("SCOPE_post:write"))))
           .andExpect(status().isCreated());
    }
}

If a security test never fails, check the filters are even running.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Spring Security course, and every lesson in it is listed on the Spring Security contents page.