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.
264 lines
8.1 KiB
264 lines
8.1 KiB
[[oauth2Client-additional-features]] |
|
= Authorized Client Features |
|
|
|
[[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 `OAuth2AuthorizedClientManager` or `OAuth2AuthorizedClientService`. |
|
|
|
==== |
|
.Java |
|
[source,java,role="primary"] |
|
---- |
|
@Controller |
|
public class OAuth2ClientController { |
|
|
|
@GetMapping("/") |
|
public String index(@RegisteredOAuth2AuthorizedClient("okta") OAuth2AuthorizedClient authorizedClient) { |
|
OAuth2AccessToken accessToken = authorizedClient.getAccessToken(); |
|
|
|
... |
|
|
|
return "index"; |
|
} |
|
} |
|
---- |
|
|
|
.Kotlin |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Controller |
|
class OAuth2ClientController { |
|
@GetMapping("/") |
|
fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2AuthorizedClient): String { |
|
val accessToken = authorizedClient.accessToken |
|
|
|
... |
|
|
|
return "index" |
|
} |
|
} |
|
---- |
|
==== |
|
|
|
The `@RegisteredOAuth2AuthorizedClient` annotation is handled by `OAuth2AuthorizedClientArgumentResolver`, which directly uses an xref:servlet/oauth2/client/core.adoc#oauth2Client-authorized-manager-provider[`OAuth2AuthorizedClientManager`] and therefore inherits it's capabilities. |
|
|
|
|
|
[[oauth2Client-webclient-servlet]] |
|
== WebClient integration for Servlet Environments |
|
|
|
The OAuth 2.0 Client support integrates with `WebClient` using an `ExchangeFilterFunction`. |
|
|
|
The `ServletOAuth2AuthorizedClientExchangeFilterFunction` 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 xref:servlet/oauth2/client/core.adoc#oauth2Client-authorized-manager-provider[`OAuth2AuthorizedClientManager`] 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 an `OAuth2AuthorizedClientProvider` 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(OAuth2AuthorizedClientManager authorizedClientManager) { |
|
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = |
|
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); |
|
return WebClient.builder() |
|
.apply(oauth2Client.oauth2Configuration()) |
|
.build(); |
|
} |
|
---- |
|
|
|
.Kotlin |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClient { |
|
val oauth2Client = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager) |
|
return WebClient.builder() |
|
.apply(oauth2Client.oauth2Configuration()) |
|
.build() |
|
} |
|
---- |
|
==== |
|
|
|
=== Providing the Authorized Client |
|
|
|
The `ServletOAuth2AuthorizedClientExchangeFilterFunction` 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 String index(@RegisteredOAuth2AuthorizedClient("okta") OAuth2AuthorizedClient authorizedClient) { |
|
String resourceUri = ... |
|
|
|
String body = webClient |
|
.get() |
|
.uri(resourceUri) |
|
.attributes(oauth2AuthorizedClient(authorizedClient)) <1> |
|
.retrieve() |
|
.bodyToMono(String.class) |
|
.block(); |
|
|
|
... |
|
|
|
return "index"; |
|
} |
|
---- |
|
|
|
.Kotlin |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@GetMapping("/") |
|
fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2AuthorizedClient): String { |
|
val resourceUri: String = ... |
|
val body: String = webClient |
|
.get() |
|
.uri(resourceUri) |
|
.attributes(oauth2AuthorizedClient(authorizedClient)) <1> |
|
.retrieve() |
|
.bodyToMono() |
|
.block() |
|
|
|
... |
|
|
|
return "index" |
|
} |
|
---- |
|
==== |
|
|
|
<1> `oauth2AuthorizedClient()` is a `static` method in `ServletOAuth2AuthorizedClientExchangeFilterFunction`. |
|
|
|
The following code shows how to set the `ClientRegistration.getRegistrationId()` as a request attribute: |
|
|
|
==== |
|
.Java |
|
[source,java,role="primary"] |
|
---- |
|
@GetMapping("/") |
|
public String index() { |
|
String resourceUri = ... |
|
|
|
String body = webClient |
|
.get() |
|
.uri(resourceUri) |
|
.attributes(clientRegistrationId("okta")) <1> |
|
.retrieve() |
|
.bodyToMono(String.class) |
|
.block(); |
|
|
|
... |
|
|
|
return "index"; |
|
} |
|
---- |
|
|
|
.Kotlin |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@GetMapping("/") |
|
fun index(): String { |
|
val resourceUri: String = ... |
|
|
|
val body: String = webClient |
|
.get() |
|
.uri(resourceUri) |
|
.attributes(clientRegistrationId("okta")) <1> |
|
.retrieve() |
|
.bodyToMono() |
|
.block() |
|
|
|
... |
|
|
|
return "index" |
|
} |
|
---- |
|
==== |
|
<1> `clientRegistrationId()` is a `static` method in `ServletOAuth2AuthorizedClientExchangeFilterFunction`. |
|
|
|
|
|
=== Defaulting the Authorized Client |
|
|
|
If neither `OAuth2AuthorizedClient` or `ClientRegistration.getRegistrationId()` is provided as a request attribute, the `ServletOAuth2AuthorizedClientExchangeFilterFunction` can determine the _default_ client to use depending on it's configuration. |
|
|
|
If `setDefaultOAuth2AuthorizedClient(true)` is configured and the user has authenticated using `HttpSecurity.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(OAuth2AuthorizedClientManager authorizedClientManager) { |
|
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = |
|
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); |
|
oauth2Client.setDefaultOAuth2AuthorizedClient(true); |
|
return WebClient.builder() |
|
.apply(oauth2Client.oauth2Configuration()) |
|
.build(); |
|
} |
|
---- |
|
|
|
.Kotlin |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClient { |
|
val oauth2Client = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager) |
|
oauth2Client.setDefaultOAuth2AuthorizedClient(true) |
|
return WebClient.builder() |
|
.apply(oauth2Client.oauth2Configuration()) |
|
.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(OAuth2AuthorizedClientManager authorizedClientManager) { |
|
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = |
|
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); |
|
oauth2Client.setDefaultClientRegistrationId("okta"); |
|
return WebClient.builder() |
|
.apply(oauth2Client.oauth2Configuration()) |
|
.build(); |
|
} |
|
---- |
|
|
|
.Kotlin |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClient { |
|
val oauth2Client = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager) |
|
oauth2Client.setDefaultClientRegistrationId("okta") |
|
return WebClient.builder() |
|
.apply(oauth2Client.oauth2Configuration()) |
|
.build() |
|
} |
|
---- |
|
==== |
|
|
|
[WARNING] |
|
It is recommended to be cautious with this feature since all HTTP requests will receive the access token.
|
|
|