-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Separate OAuth 2.0 Client Reactive Docs
Issue gh-10367
- Loading branch information
Showing
7 changed files
with
992 additions
and
1,015 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1,046 changes: 33 additions & 1,013 deletions
1,046
.../pages/reactive/oauth2/oauth2-client.adoc → ...e/oauth2/client/authorization-grants.adoc
Large diffs are not rendered by default.
Oops, something went wrong.
250 changes: 250 additions & 0 deletions
250
docs/modules/ROOT/pages/reactive/oauth2/client/authorized-clients.adoc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
[[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`. | ||
|
||
==== | ||
.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: | ||
|
||
==== | ||
.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: | ||
|
||
==== | ||
.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: | ||
|
||
==== | ||
.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: | ||
|
||
==== | ||
.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: | ||
|
||
==== | ||
.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. |
Oops, something went wrong.