Careeroza
Testing JWT and OAuth2 Endpoints
Resource Server Tests with jwt()
You do not need Keycloak running. jwt() creates an authenticated JwtAuthenticationToken directly; only the JWT decoder bean must exist, so mock it:
@WebMvcTest(OrderController.class)
@Import({ResourceServerConfig.class, JwtAuthConfig.class})
class OrderControllerJwtTest {
@Autowired MockMvc mvc;
@MockitoBean OrderService orderService;
@MockitoBean JwtDecoder jwtDecoder; // no call to the issuer during tests
@Test
void noTokenGives401() throws Exception {
mvc.perform(get("/api/orders"))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Bearer"));
}
@Test
void readScopeGives200() throws Exception {
when(orderService.findByCustomer("asha")).thenReturn(List.of());
mvc.perform(get("/api/orders").with(jwt()
.jwt(j -> j.subject("asha").claim("scope", "orders.read"))
.authorities(new SimpleGrantedAuthority("SCOPE_orders.read"))))
.andExpect(status().isOk());
}
@Test
void readScopeCannotPlaceOrders() throws Exception {
mvc.perform(post("/api/orders").contentType(MediaType.APPLICATION_JSON).content("{}")
.with(jwt().authorities(new SimpleGrantedAuthority("SCOPE_orders.read"))))
.andExpect(status().isForbidden());
}
}Note: When you pass .authorities(...) explicitly, your JwtAuthenticationConverter is skipped. To test the converter too (Keycloak realm_access mapping), use .jwt(j -> j.claim("realm_access", Map.of("roles", List.of("admin")))).authorities(converterBean) — the overload that takes a Converter<Jwt, Collection<GrantedAuthority>>.
OAuth2 Login and Opaque Tokens
// a user who logged in with Google (oauth2Login)
mvc.perform(get("/api/me").with(oidcLogin()
.idToken(token -> token.claim("email", "[email protected]").claim("name", "Asha Verma"))
.authorities(new SimpleGrantedAuthority("ROLE_CUSTOMER"))))
.andExpect(status().isOk())
.andExpect(jsonPath("$.email").value("[email protected]"));
// an opaque-token resource server
mvc.perform(get("/api/orders").with(opaqueToken()
.attributes(a -> a.put("sub", "asha"))
.authorities(new SimpleGrantedAuthority("SCOPE_orders.read"))))
.andExpect(status().isOk());Running the Tests
Maven
./mvnw -q test -Dtest="*SecurityTest,*JwtTest"Example output
[INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running in.shopease.order.OrderControllerJwtTest [INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.912 s [INFO] Running in.shopease.product.ProductControllerSecurityTest [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.284 s [INFO] Running in.shopease.order.OrderServiceSecurityTest [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.406 s [INFO] [INFO] Results: [INFO] [INFO] Tests run: 7, Failures: 0, Errors: 0, Skipped: 0 [INFO] BUILD SUCCESS
Tip: For a full end-to-end test with real tokens, start Keycloak with Testcontainers (com.github.dasniko:testcontainers-keycloak), import a test realm JSON, fetch a token and call the API with TestRestTemplate or RestClient.