Expected Behavior

Have an easy mechanism to use .with(oauth2Login()) on a service that uses the ServletOAuth2AuthorizedClientExchangeFilterFunction#setDefaultOAuth2AuthorizedClient(true) feature.

Current Behavior

When I use .with(oauth2Login()) on such service, the call isn't processed correctly, it fails as it can't find a valid AuthorizedClient in the corresponding repositories.

Context

I have this WebClient setup:

@Bean
WebClient webClient(ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientRepository authorizedClientRepository) {
    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 = new ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepository, authorizedClientRepository);
    oauth2.setDefaultOAuth2AuthorizedClient(true);
    return WebClient.builder()
        .apply(oauth2.oauth2Configuration())
        .build();
}

Note: I'm aware I should be cautious when using setDefaultOAuth2AuthorizedClient(true), but I guess it's still a valid scenario, correct?

And this simple endpoint:

@GetMapping("/projects")
public String getProjects(Model model) {
    List<ProjectModel> projects = this.webClient.get()
        .uri(projectApiUrl)
        .retrieve()
        .bodyToMono(new ParameterizedTypeReference<List<ProjectModel>>() {
        })
        .block();
    model.addAttribute("projects", projects);
    return "projects";
}

Note: I'm using block() just because I'm using WebClient in a Servlet stack.

And finally, I have this test:

@Test
void givenMockedUser_whenRequestResources_thenOK() throws Exception {
    String mockedResources = "[{\"id\":1,\"name\":\"Project 1\",\"dateCreated\":\"2015-06-01\"}]";

    resourceServer.enqueue(new MockResponse().setBody(mockedResources)
        .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE));

    mvc.perform(get("/projects")
        .with(oauth2Login())
        .accept(MediaType.APPLICATION_JSON))
        .andExpect(status().isOk())
        .andExpect(content().string(containsString("Project 1")));

    RecordedRequest request = resourceServer.takeRequest();
    assertThat(request.getHeader(HttpHeaders.AUTHORIZATION)).startsWith("Bearer");
}

This test fails with the following error message:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: Could not find ClientRegistration with id 'test'
...

Fair enough, I configure the OAuth2LoginRequestPostProcessor to use my custom ClientRegistration configured in my service:

.with(oauth2Login().clientRegistration(clientRegistrationRepository.findByRegistrationId("custom")))

Now the test fails because the service is returning a 302 response to trigger the OAuth authorization code flow, because it can't find an authorizedClient instance.

For what I understand from this note in the docs:

Further, it also links that OAuth2User to a simple instance of OAuth2AuthorizedClient that it deposits in a mock OAuth2AuthorizedClientRepository

This method does deposit the AuthorizedClient in a repository, but if understand how this works correctly, this will be stored in a HttpSessionOAuth2AuthorizedClientRepository that is not used when the WebClient resolves the AuthorizedClient using the setDefaultOAuth2AuthorizedClient feature; the OAuth2AuthorizeRequestconfigured in the ServletOAuth2AuthorizedClientExchangeFilterFunction simply has a null authorizedClient attribute.

Naturally, if I run this same test but using the @RegisteredOAuth2AuthorizedClient in the Controller endpoint, the test passes ok.

Comment From: sjohnr

@rozagerardo thanks for the report and detailed explanation! Just a note that due to the number of issues currently scheduled for 5.8 and 6.0, I have removed this from those milestones for the time being. If you are interested in submitting a PR for this, please let us know!

Comment From: rozagerardo

Thanks for having a look at this @jzheaux and for the response @sjohnr! Unfortunately, I don't have much availability to work on this right now, I'll let you know if I do at some point :)