2

In latest spring-boot-starter-oauth2-client 3.0.0-M4 classes OAuth2ProtectedResourceDetails and ClientCredentialsAccessTokenProvider have all been completely removed.

When I try to use the WebClient with non-reactive classes oAuth2 client configuration, I'm getting the following issue:

java.lang.IllegalArgumentException: principalName cannot be empty
    at org.springframework.util.Assert.hasText(Assert.java:289) ~[spring-core-6.0.0-M5.jar:6.0.0-M5]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    *__checkpoint ⇢ Request to GET http://localhost:8080/v1/notifications/2245 [DefaultWebClient]
Original Stack Trace:
        at org.springframework.util.Assert.hasText(Assert.java:289) ~[spring-core-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService.loadAuthorizedClient(InMemoryOAuth2AuthorizedClientService.java:78) ~[spring-security-oauth2-client-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager.authorize(AuthorizedClientServiceOAuth2AuthorizedClientManager.java:130) ~[spring-security-oauth2-client-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.lambda$authorizeClient$22(ServletOAuth2AuthorizedClientExchangeFilterFunction.java:470) ~[spring-security-oauth2-client-6.0.0-M6.jar:6.0.0-M6]
        at reactor.core.publisher.MonoSupplier.call(MonoSupplier.java:86) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
        at reactor.core.publisher.FluxSubscribeOnCallable$CallableSubscribeOnSubscription.run(FluxSubscribeOnCallable.java:227) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
        at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
        at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[na:na]
        at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
        at java.base/java.lang.Thread.run(Thread.java:1589) ~[na:na]
    Suppressed: java.lang.Exception: #block terminated with an error
        at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
        at reactor.core.publisher.Mono.block(Mono.java:1675) ~[reactor-core-3.5.0-M4.jar:3.5.0-M4]
        at com.example.restservice.controller.GreetingController.jwtRestcallExample(GreetingController.java:79) ~[classes/:na]
        at com.example.restservice.controller.GreetingController.greeting(GreetingController.java:56) ~[classes/:na]
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:578) ~[na:na]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) ~[spring-webmvc-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:960) ~[spring-webmvc-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) ~[spring-webmvc-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:895) ~[spring-webmvc-6.0.0-M5.jar:6.0.0-M5]
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:668) ~[tomcat-embed-core-10.0.22.jar:5.0.0]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) ~[spring-webmvc-6.0.0-M5.jar:6.0.0-M5]
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:777) ~[tomcat-embed-core-10.0.22.jar:5.0.0]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:341) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilterInternal(AuthorizationFilter.java:77) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:98) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:164) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter.doFilterInternal(BearerTokenAuthenticationFilter.java:142) ~[spring-security-oauth2-resource-server-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:116) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:350) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186) ~[spring-security-web-6.0.0-M6.jar:6.0.0-M6]
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:94) ~[spring-boot-actuator-3.0.0-M4.jar:3.0.0-M4]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.0-M5.jar:6.0.0-M5]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:356) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:867) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1760) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-10.0.22.jar:10.0.22]
        at java.base/java.lang.Thread.run(Thread.java:1589) ~[na:na]

I have configured the oauth2-client Security using non-reactive classes as below:

@Bean
@Qualifier("clientRegistrations")
@Primary
public ClientRegistrationRepository getRegistration(
        @Value("${spring.security.oauth2.client.provider.custom.token-uri}") String tokenUri,
        @Value("${spring.security.oauth2.client.registration.custom.client-id}") String clientId,
        @Value("${spring.security.oauth2.client.registration.custom.client-secret}") String clientSecret) {
    ClientRegistration registration = ClientRegistration
            .withRegistrationId("custom")
            .tokenUri(tokenUri)
            .clientId(clientId)
            .clientSecret(clientSecret)
            .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
            .build();
    return new InMemoryClientRegistrationRepository(registration);
}

@Bean
public WebClient webClientTemplate(ClientRegistrationRepository clientRegistrations) {
    InMemoryOAuth2AuthorizedClientService clientService = new InMemoryOAuth2AuthorizedClientService(clientRegistrations);
    AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrations, clientService);
    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
    oauth.setDefaultClientRegistrationId("custom");
    return WebClient.builder()
            .filter(oauth)
            .filter(errorHandler())
            .build();
}

public static ExchangeFilterFunction errorHandler() {
    return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {

        if (clientResponse.statusCode().is5xxServerError() || clientResponse.statusCode().is4xxClientError()) {
            return clientResponse.bodyToMono(String.class)
                    .flatMap(errorBody -> Mono.error(new IllegalAccessException(errorBody)));
        } else {
            return Mono.just(clientResponse);
        }
    });
}

application.yml

spring:
  security:
    oauth2:
      client:
        registration:
          custom:
            client-id: <client id>
            client-secret: <client password>
            authorization-grant-type: client_credential
        provider:
          custom:
            token-uri: <url>

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.0-M4</version>
    <relativePath/>
</parent>
<!-- Spring Boot security dependencies -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Based on solutions that are provided at Spring Security 5 Replacement for OAuth2RestTemplate recommended to use WebClient over RestTemplate and I've followed this solution but If I carefully observe the mentioned solution, which is using reactive classes from spring-boot-starter-oauth2-client 3.0.0-M4 but my application is not a reactive application. So I don't wanna end up using something which I'm not supposed to use in a non-reactive container and may cause some performance issue.

When I tried with oAuth2 client reactive classes, WebClient is working as expected but if I change all the reactive classes to non-reactive classes facing the above mentioned issue. Could anyone provide help here, what causing the issue?

Working sample configuration:

@Bean
public ReactiveClientRegistrationRepository getRegistration(
        @Value("${spring.security.oauth2.client.provider.custom.token-uri}") String tokenUri,
        @Value("${spring.security.oauth2.client.registration.custom.client-id}") String clientId,
        @Value("${spring.security.oauth2.client.registration.custom.client-secret}") String clientSecret) {
    ClientRegistration registration = ClientRegistration
            .withRegistrationId("custom")
            .tokenUri(tokenUri)
            .clientId(clientId)
            .clientSecret(clientSecret)
            .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
            .build();
    return new InMemoryReactiveClientRegistrationRepository(registration);
}

@Bean
public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
    InMemoryReactiveOAuth2AuthorizedClientService clientService = new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrations);
    AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations, clientService);
    ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
    oauth.setDefaultClientRegistrationId("custom");
    return WebClient.builder()
            .filter(oauth)
            .filter(errorHandler())
            .build();
}

public static ExchangeFilterFunction errorHandler() {
    return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
        if (clientResponse.statusCode().is5xxServerError() || clientResponse.statusCode().is4xxClientError())
            return clientResponse.bodyToMono(String.class)
                    .flatMap(errorBody -> Mono.error(new IllegalAccessException(errorBody)));
        else
            return Mono.just(clientResponse);
    });
}

1 Answers1

0

WebClient is reactive => reactive client configuration needed for it

P.S. You'd better use 3.0.0-RC2. Spring removed more classes since M4 and your prototype could be failing when moving to 3.0.0 release due by the end of the month.

ch4mp
  • 6,622
  • 6
  • 29
  • 49
  • Thanks for the answer. WebClient is reactive but `spring-boot-starter-oauth2-client` is also offering WebClient to use the non-reactive oAuth2 configuration mentioned in above such as `ClientRegistrationRepository`, `InMemoryClientRegistrationRepository`, `InMemoryOAuth2AuthorizedClientService`, `AuthorizedClientServiceOAuth2AuthorizedClientManager`, and `ServletOAuth2AuthorizedClientExchangeFilterFunction` Even [Spring Security](https://docs.spring.io/spring-security/reference/servlet/oauth2/client/authorized-clients.html) is recommended to use these terminologies for synchronous clients – Krishnakanth Yachareni Nov 18 '22 at 17:37
  • I know that web client can be used in an app that is both **synchronized** and mainly a **resource-server**, thanks. Still, WebClient is a **reactive** and **client** component and needs adapted configuration. – ch4mp Nov 18 '22 at 18:08
  • Can you check these two links: 1. [Spring security web client configuration](https://docs.spring.io/spring-security/reference/servlet/oauth2/client/authorized-clients.html) this has an example exactly what I'm talking to 2. https://stackoverflow.com/questions/63166262/can-spring-webclient-be-used-with-restful-api-which-is-not-reactive-based – Krishnakanth Yachareni Nov 18 '22 at 19:10