authorized-clients.adoc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. [[oauth2Client-additional-features]]
  2. = Authorized Client Features
  3. This section covers additional features provided by Spring Security for the OAuth2 client.
  4. [[oauth2Client-registered-authorized-client]]
  5. == Resolving an Authorized Client
  6. The `@RegisteredOAuth2AuthorizedClient` annotation provides the ability to resolve a method parameter to an argument value of type `OAuth2AuthorizedClient`.
  7. This is a convenient alternative compared to accessing the `OAuth2AuthorizedClient` by using the `OAuth2AuthorizedClientManager` or `OAuth2AuthorizedClientService`.
  8. The following example shows how to use `@RegisteredOAuth2AuthorizedClient`:
  9. ====
  10. .Java
  11. [source,java,role="primary"]
  12. ----
  13. @Controller
  14. public class OAuth2ClientController {
  15. @GetMapping("/")
  16. public String index(@RegisteredOAuth2AuthorizedClient("okta") OAuth2AuthorizedClient authorizedClient) {
  17. OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
  18. ...
  19. return "index";
  20. }
  21. }
  22. ----
  23. .Kotlin
  24. [source,kotlin,role="secondary"]
  25. ----
  26. @Controller
  27. class OAuth2ClientController {
  28. @GetMapping("/")
  29. fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2AuthorizedClient): String {
  30. val accessToken = authorizedClient.accessToken
  31. ...
  32. return "index"
  33. }
  34. }
  35. ----
  36. ====
  37. 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 its capabilities.
  38. [[oauth2Client-webclient-servlet]]
  39. == WebClient Integration for Servlet Environments
  40. The OAuth 2.0 Client support integrates with `WebClient` by using an `ExchangeFilterFunction`.
  41. The `ServletOAuth2AuthorizedClientExchangeFilterFunction` provides a mechanism for requesting protected resources by using an `OAuth2AuthorizedClient` and including the associated `OAuth2AccessToken` as a Bearer Token.
  42. It directly uses an xref:servlet/oauth2/client/core.adoc#oauth2Client-authorized-manager-provider[`OAuth2AuthorizedClientManager`] and, therefore, inherits the following capabilities:
  43. * An `OAuth2AccessToken` is requested if the client has not yet been authorized.
  44. ** `authorization_code`: Triggers the Authorization Request redirect to initiate the flow.
  45. ** `client_credentials`: The access token is obtained directly from the Token Endpoint.
  46. ** `password`: The access token is obtained directly from the Token Endpoint.
  47. * If the `OAuth2AccessToken` is expired, it is refreshed (or renewed) if an `OAuth2AuthorizedClientProvider` is available to perform the authorization
  48. The following code shows an example of how to configure `WebClient` with OAuth 2.0 Client support:
  49. ====
  50. .Java
  51. [source,java,role="primary"]
  52. ----
  53. @Bean
  54. WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
  55. ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
  56. new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
  57. return WebClient.builder()
  58. .apply(oauth2Client.oauth2Configuration())
  59. .build();
  60. }
  61. ----
  62. .Kotlin
  63. [source,kotlin,role="secondary"]
  64. ----
  65. @Bean
  66. fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClient {
  67. val oauth2Client = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
  68. return WebClient.builder()
  69. .apply(oauth2Client.oauth2Configuration())
  70. .build()
  71. }
  72. ----
  73. ====
  74. === Providing the Authorized Client
  75. The `ServletOAuth2AuthorizedClientExchangeFilterFunction` determines the client to use (for a request) by resolving the `OAuth2AuthorizedClient` from the `ClientRequest.attributes()` (request attributes).
  76. The following code shows how to set an `OAuth2AuthorizedClient` as a request attribute:
  77. ====
  78. .Java
  79. [source,java,role="primary"]
  80. ----
  81. @GetMapping("/")
  82. public String index(@RegisteredOAuth2AuthorizedClient("okta") OAuth2AuthorizedClient authorizedClient) {
  83. String resourceUri = ...
  84. String body = webClient
  85. .get()
  86. .uri(resourceUri)
  87. .attributes(oauth2AuthorizedClient(authorizedClient)) <1>
  88. .retrieve()
  89. .bodyToMono(String.class)
  90. .block();
  91. ...
  92. return "index";
  93. }
  94. ----
  95. .Kotlin
  96. [source,kotlin,role="secondary"]
  97. ----
  98. @GetMapping("/")
  99. fun index(@RegisteredOAuth2AuthorizedClient("okta") authorizedClient: OAuth2AuthorizedClient): String {
  100. val resourceUri: String = ...
  101. val body: String = webClient
  102. .get()
  103. .uri(resourceUri)
  104. .attributes(oauth2AuthorizedClient(authorizedClient)) <1>
  105. .retrieve()
  106. .bodyToMono()
  107. .block()
  108. ...
  109. return "index"
  110. }
  111. ----
  112. <1> `oauth2AuthorizedClient()` is a `static` method in `ServletOAuth2AuthorizedClientExchangeFilterFunction`.
  113. ====
  114. The following code shows how to set the `ClientRegistration.getRegistrationId()` as a request attribute:
  115. ====
  116. .Java
  117. [source,java,role="primary"]
  118. ----
  119. @GetMapping("/")
  120. public String index() {
  121. String resourceUri = ...
  122. String body = webClient
  123. .get()
  124. .uri(resourceUri)
  125. .attributes(clientRegistrationId("okta")) <1>
  126. .retrieve()
  127. .bodyToMono(String.class)
  128. .block();
  129. ...
  130. return "index";
  131. }
  132. ----
  133. .Kotlin
  134. [source,kotlin,role="secondary"]
  135. ----
  136. @GetMapping("/")
  137. fun index(): String {
  138. val resourceUri: String = ...
  139. val body: String = webClient
  140. .get()
  141. .uri(resourceUri)
  142. .attributes(clientRegistrationId("okta")) <1>
  143. .retrieve()
  144. .bodyToMono()
  145. .block()
  146. ...
  147. return "index"
  148. }
  149. ----
  150. <1> `clientRegistrationId()` is a `static` method in `ServletOAuth2AuthorizedClientExchangeFilterFunction`.
  151. ====
  152. === Defaulting the Authorized Client
  153. If neither `OAuth2AuthorizedClient` or `ClientRegistration.getRegistrationId()` is provided as a request attribute, the `ServletOAuth2AuthorizedClientExchangeFilterFunction` can determine the _default_ client to use, depending on its configuration.
  154. If `setDefaultOAuth2AuthorizedClient(true)` is configured and the user has authenticated by using `HttpSecurity.oauth2Login()`, the `OAuth2AccessToken` associated with the current `OAuth2AuthenticationToken` is used.
  155. The following code shows the specific configuration:
  156. ====
  157. .Java
  158. [source,java,role="primary"]
  159. ----
  160. @Bean
  161. WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
  162. ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
  163. new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
  164. oauth2Client.setDefaultOAuth2AuthorizedClient(true);
  165. return WebClient.builder()
  166. .apply(oauth2Client.oauth2Configuration())
  167. .build();
  168. }
  169. ----
  170. .Kotlin
  171. [source,kotlin,role="secondary"]
  172. ----
  173. @Bean
  174. fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClient {
  175. val oauth2Client = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
  176. oauth2Client.setDefaultOAuth2AuthorizedClient(true)
  177. return WebClient.builder()
  178. .apply(oauth2Client.oauth2Configuration())
  179. .build()
  180. }
  181. ----
  182. ====
  183. [WARNING]
  184. ====
  185. Be cautious with this feature, since all HTTP requests receive the access token.
  186. ====
  187. Alternatively, if `setDefaultClientRegistrationId("okta")` is configured with a valid `ClientRegistration`, the `OAuth2AccessToken` associated with the `OAuth2AuthorizedClient` is used.
  188. The following code shows the specific configuration:
  189. ====
  190. .Java
  191. [source,java,role="primary"]
  192. ----
  193. @Bean
  194. WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
  195. ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
  196. new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
  197. oauth2Client.setDefaultClientRegistrationId("okta");
  198. return WebClient.builder()
  199. .apply(oauth2Client.oauth2Configuration())
  200. .build();
  201. }
  202. ----
  203. .Kotlin
  204. [source,kotlin,role="secondary"]
  205. ----
  206. @Bean
  207. fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClient {
  208. val oauth2Client = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
  209. oauth2Client.setDefaultClientRegistrationId("okta")
  210. return WebClient.builder()
  211. .apply(oauth2Client.oauth2Configuration())
  212. .build()
  213. }
  214. ----
  215. ====
  216. [WARNING]
  217. ====
  218. Be cautious with this feature, since all HTTP requests receive the access token.
  219. ====