authorized-clients.adoc 8.2 KB

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