I began a fresh project with WebFlux and aimed to access an API using OAuth2 authorization. While the official documentation provided some guidance on setting up OAuth2 with WebFlux, it didn’t fully address my specific scenario. Consequently, I turned to Baeldung’s article titled Spring Security OAuth Login with WebFlux for additional insights. However, upon implementing the solution outlined in the article, I encountered an exception—specifically, the UnAuthenticatedServerOAuth2AuthorizedClientRepository exception—upon starting the application.

<dependency>
    <groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Following that, proceed to include configuration details in the src/main/resources/application.yml file. In this instance, your client will be identified by the key “pet-finder.” This key serves as a registration ID and will be essential for subsequent steps. It’s worth noting that you can accommodate multiple OAuth configurations, and these registration ID’s will serve to differentiate them.

spring.security.oauth2.client:
    provider.pet-finder.token-uri: "https://api.petfinder.com/v2/oauth2/token"
    registration.pet-finder.authorization-grant-type: "client_credentials"

Next, establish configuration with a WebClient bean. In order to authenticate with the Petfinder API, the WebClient must be augmented with a filter – ServerOAuth2AuthorizedClientExchangeFilterFunction. Employing the registration ID “pet-finder” established earlier, configure the token URI and authorization grant type accordingly.

@Configuration
class PetFinderConfiguration {
    @Bean
    WebClient petFinderClient(
        clientRegistrations: ReactiveClientRegistrationRepository, 
        clientRepository: ServerOAuth2AuthorizedClientRepository
    ) {
        val filter = serverOAuth2AuthorizedClientExchangeFilterFunction(
            clientRegistrations, 
            clientRepository
        )
        filter.setDefaultClientRegistrationId("pet-finder")
        return WebClient.builder()
            .filter(filter)
            .build()
    }
}

To properly configure your client ID and secret for your Spring application, it’s essential not to embed them directly into your source code. Storing secrets within the code itself can lead to security risks. Instead, it’s recommended to pass them as arguments when starting your Spring application. When using Maven, you can achieve this with the following command:

./mvnw spring-boot:run -Dspring-boot.run.arguments=--spring.security.oauth2.client.registration.pet-finder.client-secret=YOUR_SECRET,--spring.security.oauth2.client.registration.pet-finder.client-id=YOUR_ID

Now, with this setup, you’re ready to utilize the WebClient to retrieve details about pets awaiting adoption.

@Component
class AnimalsService(private val petFinderClient: WebClient) {
    fun fetch(): Flux<Animal> = petFinderClient
        .get()
        .uri("https://api.petfinder.com/v2/animals")
        .retrieve()
        .bodyToMono(Payload::class.java)
        .flatMapIterable { it.animals }
}


data class Payload(val animals: Set<Animal>)
data class Animal(val id: String, val name: String, val species: String)

My site is free of ads and trackers. Was this post helpful to you? Why not BuyMeACoffee


Reference:

  1. OAuth2 with WebFlux
  2. Spring Security OAuth Login with WebFlux
  3. https://start.spring.io
  4. Spring Boot Reactive WebClient “serverWebExchange must be null” when Spring Security OAuth is in use
  5. Working Effectively with Legacy Code
  6. Designing Event-Driven Systems
  7. API calls - petfinder