123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- = WebClient
- [NOTE]
- ====
- The following documentation is for use within Reactive environments.
- For Servlet environments, refer to <<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()
- ----
- ====
|