In a Spring Boot 3.2.2 application, I have a controller that will look at the Oauth2 token from the request, and behaves differently according to what it finds. The token is provided by Auth0 / Okta .
It works as expected, but I want to write a test for my controller :
@WebMvcTest(MembersController::class)
class MembersControllerTest(@Autowired val mockMvc: MockMvc) {
@Test
fun `should return 403 when name in token is unknown`() {
val oauth2User = DefaultOAuth2User(
setOf(), // Authorities
mapOf("sub" to "123", "name" to "someUnknownName", "email" to "[email protected]"),
"sub"
)
mockMvc.post("/api/v1/members") {
with(oauth2Login().oauth2User(oauth2User))
}
.andExpect {
status { isUnauthorized() }
}
}
}
When I run the test, I get this error
ERROR org.springframework.boot.SpringApplication -- Application run failed java.lang.IllegalArgumentException: URI is not absolute
In debug, I see the URL that has a problem is /.well-known/openid-configuration .
In the stacktrace, I see it's related to the okta starter
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:781)
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:422)
at com.okta.spring.boot.oauth.env.OktaOAuth2PropertiesMappingEnvironmentPostProcessor.postProcessEnvironment(OktaOAuth2PropertiesMappingEnvironmentPostProcessor.java:122)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:109)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:94)
I was not expecting that this would happens with @WebMvcTest..
Is there a way to workaround this and use @WebMvcTest ? or do I need to test this at a higher level with @SpringBootTest and send real requests with real tokens ?
First, the
oauth2Login()post-processor you are using is designed for OAuth2 clients withoauth2Login(), not for resource servers authorizing requests with a JWT decoderoauth2ResourceServer(rs -> rs.jwt(...)). You should probably be using thejwt()post-processor.In a
@WebMvcTestof an OAuth2 resource server with a JWT decoder, you should@MockBean JwtDecoder jwtDecoder;and use either:SecurityMockMvcRequestPostProcessors.jwt()fromspring-security-test@WithJwtfromspring-addons-oauth2-testDisclaimer: same author for both (myself), and is the same for this Baeldung article covering the subject.
Edit
What I expose above is not enough with Okta Spring Boot starter and it seems pretty difficult to mock some of the beans it defines and which throw an exception if it can't access the authorization server (which is a problem for unit tests).
Alternatively to Okta starter, you could use this one I wrote. It is designed to work with any OpenID Provider: Okta, but also Auth0 (including the handling of
audienceparameter on authorization & token endpoints, and the non exactly standard RP-Initiated Logout), Keycloak, Amazon Cognito, and many others.src/test/resources/user.json:remember to change the
issclaim in your test resources when you update theissin yourapplication.yml