skip to content

Test Annotations: @WithMockUser

@WithMockUser, @WithUserDetails and custom @WithSecurityContext factories populate a security context so a slice test can exercise a secured method. The standard answer to 'how do you test @PreAuthorize'.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What does @WithMockUser do in a Spring Security test, and what are its defaults?

level: juniorimportance: must knowfreq 78%

answer

  1. default user/password/ROLE_USER
  2. roles auto-prefixed ROLE_
  3. authorities used verbatim
  4. not from DB — fabricated principal
  5. listener writes SecurityContextHolder

basics

~10 s

@WithMockUser runs a test as if a logged-in user made the request, without hitting a real login. By default the user is named 'user' with password 'password' and the role USER.

solid answer

~30 s

@WithMockUser (from spring-security-test) populates the SecurityContext before a test method so your code runs as an authenticated user without a real login flow. Defaults: username 'user', password 'password', a single authority 'ROLE_USER'. You override with attributes: username, roles (each auto-prefixed with 'ROLE_'), authorities (used verbatim, no prefix), and password. Put it on a test method or the whole class; method-level wins over class-level. It works with @WebMvcTest/@SpringBootTest + MockMvc because a WithSecurityContextTestExecutionListener writes the mock Authentication into the SecurityContextHolder for the duration of the test.

code

java · 26 lines
java
@WebMvcTest(AdminController.class)
class AdminControllerTest {

    @Autowired MockMvc mvc;

    @Test
    @WithMockUser // username="user", authority ROLE_USER
    void plainUserForbiddenFromAdmin() throws Exception {
        mvc.perform(get("/admin"))
           .andExpect(status().isForbidden());
    }

    @Test
    @WithMockUser(username = "alice", roles = {"ADMIN"}) // -> ROLE_ADMIN
    void adminCanAccess() throws Exception {
        mvc.perform(get("/admin"))
           .andExpect(status().isOk());
    }

    @Test
    @WithMockUser(authorities = {"SCOPE_admin:read"}) // verbatim, no ROLE_ prefix
    void scopeBasedAccess() throws Exception {
        mvc.perform(get("/admin"))
           .andExpect(status().isOk());
    }
}

go deeper

for a junior

Know it fakes a logged-in user with defaults user/ROLE_USER and where you place it.

for a middle

Explain roles (auto-prefixed) vs authorities (verbatim) and the mutual-exclusivity rule.

for a senior

Explain the listener mechanism, override precedence, and when to reach for @WithUserDetails instead.

for a principal

Discuss classpath/listener wiring, TestSecurityContextHolder, and reactive vs servlet propagation nuances.

## What it is `@WithMockUser` is a test annotation from the **spring-security-test** module (`org.springframework.security.test.context.support.WithMockUser`). It lets a test execute as though an authenticated user is present, **without** performing a real authentication (no login form, no JWT, no password check). This matters because method-security (`@PreAuthorize`, `@Secured`) and URL-security (`authorizeHttpRequests`) read the current user from the **SecurityContext**, and in a test there is normally no logged-in user. ## How it populates the SecurityContext Spring Security registers a `WithSecurityContextTestExecutionListener` (auto-discovered via spring-security-test on the classpath). Before your test method runs, it reads the annotation, builds a `SecurityContext` containing a `UsernamePasswordAuthenticationToken`, and stores it in the **`TestSecurityContextHolder`**, which in turn sets Spring Security's `SecurityContextHolder`. After the test it is cleared. ## The principal it builds The `Authentication` holds a `org.springframework.security.core.userdetails.User` as the principal, with: - **username** — default `"user"`. - **password** — default `"password"` (rarely relevant in tests). - **authorities** — default a single `SimpleGrantedAuthority("ROLE_USER")`. ## Attributes and their semantics - `username` / `value` — sets the principal name. `value` is an alias, so `@WithMockUser("alice")` == `@WithMockUser(username = "alice")`. - `roles` — a String array; **each entry is automatically prefixed with `ROLE_`**. So `roles = {"ADMIN"}` yields authority `ROLE_ADMIN`. **Do NOT include the prefix yourself** — `roles = {"ROLE_ADMIN"}` throws `IllegalArgumentException` because the resulting `ROLE_ROLE_ADMIN` is rejected. - `authorities` — a String array used **verbatim** (no prefixing). Use this for non-role authorities like `"SCOPE_read"` or `"READ_PRIVILEGE"`. - `roles` and `authorities` are **mutually exclusive** when both are non-default — setting both throws an `IllegalStateException`. - `password` — sets the principal password. - `setupBefore` — a `TestExecutionEvent` controlling *when* the context is set (see the custom-factory question); default is `TEST_METHOD`. ## Placement and override rules Apply it at **method** level (that test only) or **class** level (every method). A method-level annotation overrides a class-level one for that method. To make one method run *unauthenticated* while the class is annotated, use `@WithAnonymousUser` on that method. ## Common gotchas - The mock user is **not** loaded from your `UserDetailsService` or database — it is a fabricated principal. If you need your real user (with real authorities/fields), use `@WithUserDetails`. - `roles` vs `authorities` confusion is the #1 mistake: `@PreAuthorize("hasRole('ADMIN')")` checks for `ROLE_ADMIN`, so use `roles = {"ADMIN"}`; `hasAuthority('ROLE_ADMIN')` needs the full string. - Requires **spring-security-test** on the test classpath and a Spring `TestContext` (e.g. `@ExtendWith(SpringExtension.class)`, which `@SpringBootTest`/`@WebMvcTest` provide). A plain unit test with no Spring context ignores it. ## When to use Slice tests (`@WebMvcTest`) and integration tests (`@SpringBootTest`) where you want to assert authorization behavior for a *generic* authenticated user and don't need a real database-backed principal.

  • Your test uses @WithMockUser(roles = {"ADMIN"}) but @PreAuthorize("hasAuthority('ADMIN')") still denies access. Why?
    roles auto-prefixes to ROLE_ADMIN, but hasAuthority('ADMIN') checks the literal string 'ADMIN' with no prefix. Either use hasRole('ADMIN') (which adds ROLE_) or switch to authorities = {"ADMIN"}.
  • Does @WithMockUser require spring-security-test and a Spring context?
    Yes. It needs spring-security-test on the classpath (which registers WithSecurityContextTestExecutionListener) and a Spring TestContext such as the one provided by @SpringBootTest or @WebMvcTest. A pure unit test with no Spring context ignores it.

saying these in an interview costs you the question

  • Thinking @WithMockUser loads the user from the database / UserDetailsService
  • Adding the ROLE_ prefix yourself in roles = {"ROLE_ADMIN"}
  • Believing roles and authorities can both be set to non-default values
  • Assuming it works without spring-security-test on the classpath

context

open as a page

When would you use @WithUserDetails instead of @WithMockUser?

level: middleimportance: must knowfreq 62%

basics

~10 s

@WithMockUser fabricates a fake user from annotation attributes. @WithUserDetails loads a real user through your UserDetailsService, so the test uses the same principal type, authorities, and fields your app produces.

open as a page

What is @WithAnonymousUser for, and how does annotation precedence work at class vs method level?

level: middleimportance: should knowfreq 40%

basics

~10 s

@WithAnonymousUser runs a test as an unauthenticated (anonymous) user. It's mainly used to override a class-level @WithMockUser on one specific method that should test the not-logged-in case.

open as a page

How do you build a custom test annotation with @WithSecurityContext and a WithSecurityContextFactory?

level: seniorimportance: should knowfreq 34%

basics

~10 s

Create your own annotation meta-annotated with @WithSecurityContext(factory = MyFactory.class), then implement WithSecurityContextFactory<YourAnnotation> to build and return a SecurityContext. The listener puts that context into the SecurityContextHolder for the test.

open as a page

How do these context annotations behave in reactive WebFlux tests, and what is the idiomatic WebTestClient alternative?

level: principalimportance: should knowfreq 26%

basics

~20 s

In WebFlux, security is read from the reactive context, not a thread-local. @WithMockUser still works in @WebFluxTest slices, but for WebTestClient the idiomatic approach is client.mutateWith(SecurityMockServerConfigurers.mockUser()), which injects the principal into the reactive request context.

open as a page