Spring Security 5 Calling OAuth2 Secured API in Application Runner results in IllegalArgumentException

Since I also stumbled across this problem I'll elaborate a bit on Darren Forsythe's updated answer to make it easier for others to find:

The issue submitted by the OP resulted in an implementation of OAuth2AuthorizedClientManager that is capable of

operating outside of a HttpServletRequest context, e.g. in a scheduled/background thread and/or in the service-tier

(from the official docs)

Said implementation, the AuthorizedClientServiceOAuth2AuthorizedClientManager, is passed to the ServletOAuth2AuthorizedClientExchangeFilterFunction to replace the default one.

In my example this looks something like this:

@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
        ClientRegistrationRepository clientRegistrationRepository,
        OAuth2AuthorizedClientService clientService)
{

    OAuth2AuthorizedClientProvider authorizedClientProvider = 
        OAuth2AuthorizedClientProviderBuilder.builder()
            .clientCredentials()
            .build();

    AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = 
        new AuthorizedClientServiceOAuth2AuthorizedClientManager(
            clientRegistrationRepository, clientService);
    authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

    return authorizedClientManager;
}

@Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager)
{
    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 =
        new ServletOAuth2AuthorizedClientExchangeFilterFunction(
            authorizedClientManager);
    oauth2.setDefaultClientRegistrationId("keycloak");
    return WebClient.builder().apply(oauth2.oauth2Configuration()).build();
}

I ended up asking this to the Spring Security team,

https://github.com/spring-projects/spring-security/issues/6683

Unfortunately if you are on the servlet stack and calling to OAuth2 resources with pure Spring Security 5 APIs in a background thread there isn't a OAuth2AuthorizedClientRepository available.

Realistically there's two options,

  1. Implement a completely no-op version,
 var oauth2 = new ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepo,
                        new OAuth2AuthorizedClientRepository() {
                            @Override
                            public <T extends OAuth2AuthorizedClient> T loadAuthorizedClient(String s,
                                    Authentication authentication, HttpServletRequest httpServletRequest) {
                                return null;
                            }

                            @Override
                            public void saveAuthorizedClient(OAuth2AuthorizedClient oAuth2AuthorizedClient,
                                    Authentication authentication, HttpServletRequest httpServletRequest,
                                    HttpServletResponse httpServletResponse) {

                            }

                            @Override
                            public void removeAuthorizedClient(String s, Authentication authentication,
                                    HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {

                            }
                        });
  1. Implement a Servlet Version of UnAuthenticatedServerOAuth2AuthorizedClientRepository. UnAuthenticatedServerOAuth2AuthorizedClientRepository GitHub Source which has some basic functionality than a pure no-op.

Providing feedback on the GitHub issue might help the Spring Security team to evaluate accepting a PR and maintaining a Servlet version of the UnAuthenticatedServerOAuth2AuthorizedClientRepository

I reached out the the Spring Security Team Spring Security Issue 6683 and on the back of that a Servlet version of the ServerOAuth2AuthorizedClientExchangeFilterFunction will be added in Spring Security 5.2 for usage on non-http threads.