123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- [[oauth2Client-additional-features]]
- = Authorized Clients
- [[oauth2Client-registered-authorized-client]]
- == Resolving an Authorized Client
- The `@RegisteredOAuth2AuthorizedClient` annotation provides the capability of resolving a method parameter to an argument value of type `OAuth2AuthorizedClient`.
- This is a convenient alternative compared to accessing the `OAuth2AuthorizedClient` using the `ReactiveOAuth2AuthorizedClientManager` or `ReactiveOAuth2AuthorizedClientService`.
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- @Controller
- public class OAuth2ClientController {
- @GetMapping("/")
- public Mono<String> index(@RegisteredOAuth2AuthorizedClient("okta") OAuth2AuthorizedClient authorizedClient) {
- return Mono.just(authorizedClient.getAccessToken())
- ...
- .thenReturn("index");
- }
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- @Controller
- class OAuth2ClientController {
- @GetMapping("/")
- fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2AuthorizedClient): Mono<String> {
- return Mono.just(authorizedClient.accessToken)
- ...
- .thenReturn("index")
- }
- }
- ----
- ======
- The `@RegisteredOAuth2AuthorizedClient` annotation is handled by `OAuth2AuthorizedClientArgumentResolver`, which directly uses a <<oauth2Client-authorized-manager-provider, ReactiveOAuth2AuthorizedClientManager>> and therefore inherits it's capabilities.
- [[oauth2Client-webclient-webflux]]
- == WebClient integration for Reactive Environments
- The OAuth 2.0 Client support integrates with `WebClient` using an `ExchangeFilterFunction`.
- The `ServerOAuth2AuthorizedClientExchangeFilterFunction` provides a simple mechanism for requesting protected resources by using an `OAuth2AuthorizedClient` and including the associated `OAuth2AccessToken` as a Bearer Token.
- It directly uses an <<oauth2Client-authorized-manager-provider, ReactiveOAuth2AuthorizedClientManager>> and therefore inherits the following capabilities:
- * An `OAuth2AccessToken` will be requested if the client has not yet been authorized.
- ** `authorization_code` - triggers the Authorization Request redirect to initiate the flow
- ** `client_credentials` - the access token is obtained directly from the Token Endpoint
- ** `password` - the access token is obtained directly from the Token Endpoint
- * If the `OAuth2AccessToken` is expired, it will be refreshed (or renewed) if a `ReactiveOAuth2AuthorizedClientProvider` is available to perform the authorization
- The following code shows an example of how to configure `WebClient` with OAuth 2.0 Client support:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- @Bean
- WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
- ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
- new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
- return WebClient.builder()
- .filter(oauth2Client)
- .build();
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- @Bean
- fun webClient(authorizedClientManager: ReactiveOAuth2AuthorizedClientManager): WebClient {
- val oauth2Client = ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
- return WebClient.builder()
- .filter(oauth2Client)
- .build()
- }
- ----
- ======
- === Providing the Authorized Client
- The `ServerOAuth2AuthorizedClientExchangeFilterFunction` determines the client to use (for a request) by resolving the `OAuth2AuthorizedClient` from the `ClientRequest.attributes()` (request attributes).
- The following code shows how to set an `OAuth2AuthorizedClient` as a request attribute:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- @GetMapping("/")
- public Mono<String> index(@RegisteredOAuth2AuthorizedClient("okta") OAuth2AuthorizedClient authorizedClient) {
- String resourceUri = ...
- return webClient
- .get()
- .uri(resourceUri)
- .attributes(oauth2AuthorizedClient(authorizedClient)) <1>
- .retrieve()
- .bodyToMono(String.class)
- ...
- .thenReturn("index");
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- @GetMapping("/")
- fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2AuthorizedClient): Mono<String> {
- val resourceUri: String = ...
- return webClient
- .get()
- .uri(resourceUri)
- .attributes(oauth2AuthorizedClient(authorizedClient)) <1>
- .retrieve()
- .bodyToMono<String>()
- ...
- .thenReturn("index")
- }
- ----
- ======
- <1> `oauth2AuthorizedClient()` is a `static` method in `ServerOAuth2AuthorizedClientExchangeFilterFunction`.
- The following code shows how to set the `ClientRegistration.getRegistrationId()` as a request attribute:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- @GetMapping("/")
- public Mono<String> index() {
- String resourceUri = ...
- return webClient
- .get()
- .uri(resourceUri)
- .attributes(clientRegistrationId("okta")) <1>
- .retrieve()
- .bodyToMono(String.class)
- ...
- .thenReturn("index");
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- @GetMapping("/")
- fun index(): Mono<String> {
- val resourceUri: String = ...
- return webClient
- .get()
- .uri(resourceUri)
- .attributes(clientRegistrationId("okta")) <1>
- .retrieve()
- .bodyToMono<String>()
- ...
- .thenReturn("index")
- }
- ----
- ======
- <1> `clientRegistrationId()` is a `static` method in `ServerOAuth2AuthorizedClientExchangeFilterFunction`.
- === Defaulting the Authorized Client
- If neither `OAuth2AuthorizedClient` or `ClientRegistration.getRegistrationId()` is provided as a request attribute, the `ServerOAuth2AuthorizedClientExchangeFilterFunction` can determine the _default_ client to use depending on it's configuration.
- If `setDefaultOAuth2AuthorizedClient(true)` is configured and the user has authenticated using `ServerHttpSecurity.oauth2Login()`, the `OAuth2AccessToken` associated with the current `OAuth2AuthenticationToken` is used.
- The following code shows the specific configuration:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- @Bean
- WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
- ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
- new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
- oauth2Client.setDefaultOAuth2AuthorizedClient(true);
- return WebClient.builder()
- .filter(oauth2Client)
- .build();
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- @Bean
- fun webClient(authorizedClientManager: ReactiveOAuth2AuthorizedClientManager): WebClient {
- val oauth2Client = ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
- oauth2Client.setDefaultOAuth2AuthorizedClient(true)
- return WebClient.builder()
- .filter(oauth2Client)
- .build()
- }
- ----
- ======
- [WARNING]
- It is recommended to be cautious with this feature since all HTTP requests will receive the access token.
- Alternatively, if `setDefaultClientRegistrationId("okta")` is configured with a valid `ClientRegistration`, the `OAuth2AccessToken` associated with the `OAuth2AuthorizedClient` is used.
- The following code shows the specific configuration:
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- @Bean
- WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
- ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
- new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
- oauth2Client.setDefaultClientRegistrationId("okta");
- return WebClient.builder()
- .filter(oauth2Client)
- .build();
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- @Bean
- fun webClient(authorizedClientManager: ReactiveOAuth2AuthorizedClientManager): WebClient {
- val oauth2Client = ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
- oauth2Client.setDefaultClientRegistrationId("okta")
- return WebClient.builder()
- .filter(oauth2Client)
- .build()
- }
- ----
- ======
- [WARNING]
- It is recommended to be cautious with this feature since all HTTP requests will receive the access token.
|