You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
5.3 KiB
175 lines
5.3 KiB
= WebClient |
|
|
|
[NOTE] |
|
==== |
|
The following documentation is for use within Reactive environments. |
|
For Servlet environments, refer to xref:servlet/oauth2/oauth2-client.adoc#oauth2Client-webclient-servlet[ WebClient for Servlet] environments. |
|
==== |
|
|
|
|
|
Spring Framework has built in support for setting a Bearer token. |
|
|
|
==== |
|
.Java |
|
[source,java,role="primary"] |
|
---- |
|
webClient.get() |
|
.headers(h -> h.setBearerAuth(token)) |
|
... |
|
---- |
|
|
|
.Kotlin |
|
[source,kotlin,role="secondary"] |
|
---- |
|
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-setup]] |
|
== 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 |
|
[source,java,role="primary"] |
|
---- |
|
@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 |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@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() |
|
} |
|
---- |
|
==== |
|
|
|
[[webclient-implicit]] |
|
== 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 |
|
[source,java,role="primary"] |
|
---- |
|
Mono<String> body = this.webClient |
|
.get() |
|
.uri(this.uri) |
|
.retrieve() |
|
.bodyToMono(String.class); |
|
---- |
|
|
|
.Kotlin |
|
[source,kotlin,role="secondary"] |
|
---- |
|
val body: Mono<String> = webClient |
|
.get() |
|
.uri(this.uri) |
|
.retrieve() |
|
.bodyToMono() |
|
---- |
|
==== |
|
|
|
[[webclient-explicit]] |
|
== 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 |
|
[source,java,role="primary"] |
|
---- |
|
@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 |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@GetMapping("/explicit") |
|
fun explicit(@RegisteredOAuth2AuthorizedClient("client-id") authorizedClient: OAuth2AuthorizedClient?): Mono<String> { |
|
return this.webClient |
|
.get() |
|
.uri(uri) |
|
.attributes(oauth2AuthorizedClient(authorizedClient)) |
|
.retrieve() |
|
.bodyToMono() |
|
} |
|
---- |
|
==== |
|
|
|
[[webclient-clientregistrationid]] |
|
== 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 |
|
[source,java,role="primary"] |
|
---- |
|
Mono<String> body = this.webClient |
|
.get() |
|
.uri(this.uri) |
|
.attributes(clientRegistrationId("client-id")) |
|
.retrieve() |
|
.bodyToMono(String.class); |
|
---- |
|
|
|
.Kotlin |
|
[source,kotlin,role="secondary"] |
|
---- |
|
val body: Mono<String> = this.webClient |
|
.get() |
|
.uri(uri) |
|
.attributes(clientRegistrationId("client-id")) |
|
.retrieve() |
|
.bodyToMono() |
|
---- |
|
====
|
|
|