WebClient

The following documentation is for use within Reactive environments. For Servlet environments, refer to WebClient for Servlet environments.

Spring Framework has built in support for setting a Bearer token.

Java
webClient.get()
    .headers(h -> h.setBearerAuth(token))
    ...
Kotlin
webClient.get()
    .headers { it.setBearerAuth(token) }
    ...

Spring Security builds on this support to provide additional benefits:

  • Spring Security will automatically refresh expired tokens (if a refresh token is present)

  • If an access token is requested and not present, Spring Security will automatically request the access token.

    • For authorization_code this involves performing the redirect and then replaying the original request

    • For client_credentials the token is simply requested and saved

  • Support for the ability to transparently include the current OAuth token or explicitly select which token should be used.

WebClient OAuth2 Setup

The first step is ensuring to setup the WebClient correctly. An example of setting up WebClient in a fully reactive environment can be found below:

Java
@Bean
WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations,
		ServerOAuth2AuthorizedClientRepository authorizedClients) {
	ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
			new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients);
	// (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
	// oauth.setDefaultOAuth2AuthorizedClient(true);
	// (optional) set a default ClientRegistration.registrationId
	// oauth.setDefaultClientRegistrationId("client-registration-id");
	return WebClient.builder()
			.filter(oauth)
			.build();
}
Kotlin
@Bean
fun webClient(clientRegistrations: ReactiveClientRegistrationRepository,
              authorizedClients: ServerOAuth2AuthorizedClientRepository): WebClient {
    val oauth = ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations, authorizedClients)
    // (optional) explicitly opt into using the oauth2Login to provide an access token implicitly
    // oauth.setDefaultOAuth2AuthorizedClient(true)
    // (optional) set a default ClientRegistration.registrationId
    // oauth.setDefaultClientRegistrationId("client-registration-id")
    return WebClient.builder()
            .filter(oauth)
            .build()
}

Implicit OAuth2AuthorizedClient

If we set defaultOAuth2AuthorizedClient to true in our setup and the user authenticated with oauth2Login (i.e. OIDC), then the current authentication is used to automatically provide the access token. Alternatively, if we set defaultClientRegistrationId to a valid ClientRegistration id, that registration is used to provide the access token. This is convenient, but in environments where not all endpoints should get the access token, it is dangerous (you might provide the wrong access token to an endpoint).

Java
Mono<String> body = this.webClient
		.get()
		.uri(this.uri)
		.retrieve()
		.bodyToMono(String.class);
Kotlin
val body: Mono<String> = webClient
        .get()
        .uri(this.uri)
        .retrieve()
        .bodyToMono()

Explicit OAuth2AuthorizedClient

The OAuth2AuthorizedClient can be explicitly provided by setting it on the requests attributes. In the example below we resolve the OAuth2AuthorizedClient using Spring WebFlux or Spring MVC argument resolver support. However, it does not matter how the OAuth2AuthorizedClient is resolved.

Java
@GetMapping("/explicit")
Mono<String> explicit(@RegisteredOAuth2AuthorizedClient("client-id") OAuth2AuthorizedClient authorizedClient) {
	return this.webClient
			.get()
			.uri(this.uri)
			.attributes(oauth2AuthorizedClient(authorizedClient))
			.retrieve()
			.bodyToMono(String.class);
}
Kotlin
@GetMapping("/explicit")
fun explicit(@RegisteredOAuth2AuthorizedClient("client-id") authorizedClient: OAuth2AuthorizedClient?): Mono<String> {
    return this.webClient
            .get()
            .uri(uri)
            .attributes(oauth2AuthorizedClient(authorizedClient))
            .retrieve()
            .bodyToMono()
}

clientRegistrationId

Alternatively, it is possible to specify the clientRegistrationId on the request attributes and the WebClient will attempt to lookup the OAuth2AuthorizedClient. If it is not found, one will automatically be acquired.

Java
Mono<String> body = this.webClient
		.get()
		.uri(this.uri)
		.attributes(clientRegistrationId("client-id"))
		.retrieve()
		.bodyToMono(String.class);
Kotlin
val body: Mono<String> = this.webClient
        .get()
        .uri(uri)
        .attributes(clientRegistrationId("client-id"))
        .retrieve()
        .bodyToMono()