authorization-grants.adoc 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527
  1. [[oauth2-client-authorization-grants]]
  2. = [[oauth2Client-auth-grant-support]]Authorization Grant Support
  3. :spring-security-reference-base-url: https://docs.spring.io/spring-security/reference
  4. This section describes Spring Security's support for authorization grants.
  5. [[oauth2-client-authorization-code]]
  6. == [[oauth2Client-auth-code-grant]]Authorization Code
  7. [NOTE]
  8. ====
  9. See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.1[Authorization Code] grant.
  10. ====
  11. [[oauth2-client-authorization-code-authorization]]
  12. === Obtaining Authorization
  13. [NOTE]
  14. ====
  15. See the https://tools.ietf.org/html/rfc6749#section-4.1.1[Authorization Request/Response] protocol flow for the Authorization Code grant.
  16. ====
  17. [[oauth2-client-authorization-code-authorization-request]]
  18. === Initiating the Authorization Request
  19. The `OAuth2AuthorizationRequestRedirectFilter` uses an `OAuth2AuthorizationRequestResolver` to resolve an `OAuth2AuthorizationRequest` and initiate the Authorization Code grant flow by redirecting the end-user's user-agent to the Authorization Server's Authorization Endpoint.
  20. The primary role of the `OAuth2AuthorizationRequestResolver` is to resolve an `OAuth2AuthorizationRequest` from the provided web request.
  21. The default implementation `DefaultOAuth2AuthorizationRequestResolver` matches on the (default) path `+/oauth2/authorization/{registrationId}+`, extracting the `registrationId`, and using it to build the `OAuth2AuthorizationRequest` for the associated `ClientRegistration`.
  22. Consider the following Spring Boot properties for an OAuth 2.0 Client registration:
  23. [source,yaml,attrs="-attributes"]
  24. ----
  25. spring:
  26. security:
  27. oauth2:
  28. client:
  29. registration:
  30. okta:
  31. client-id: okta-client-id
  32. client-secret: okta-client-secret
  33. authorization-grant-type: authorization_code
  34. redirect-uri: "{baseUrl}/authorized/okta"
  35. scope: read, write
  36. provider:
  37. okta:
  38. authorization-uri: https://dev-1234.oktapreview.com/oauth2/v1/authorize
  39. token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
  40. ----
  41. Given the preceding properties, a request with the base path `/oauth2/authorization/okta` initiates the Authorization Request redirect by the `OAuth2AuthorizationRequestRedirectFilter` and ultimately starts the Authorization Code grant flow.
  42. [NOTE]
  43. ====
  44. The `AuthorizationCodeOAuth2AuthorizedClientProvider` is an implementation of `OAuth2AuthorizedClientProvider` for the Authorization Code grant,
  45. which also initiates the Authorization Request redirect by the `OAuth2AuthorizationRequestRedirectFilter`.
  46. ====
  47. If the OAuth 2.0 Client is a https://tools.ietf.org/html/rfc6749#section-2.1[Public Client], configure the OAuth 2.0 Client registration as follows:
  48. [source,yaml,attrs="-attributes"]
  49. ----
  50. spring:
  51. security:
  52. oauth2:
  53. client:
  54. registration:
  55. okta:
  56. client-id: okta-client-id
  57. client-authentication-method: none
  58. authorization-grant-type: authorization_code
  59. redirect-uri: "{baseUrl}/authorized/okta"
  60. # ...
  61. ----
  62. Public Clients are supported by using https://tools.ietf.org/html/rfc7636[Proof Key for Code Exchange] (PKCE).
  63. If the client is running in an untrusted environment (such as a native application or web browser-based application) and is therefore incapable of maintaining the confidentiality of its credentials, PKCE is automatically used when the following conditions are true:
  64. . `client-secret` is omitted (or empty)
  65. . `client-authentication-method` is set to `none` (`ClientAuthenticationMethod.NONE`)
  66. [TIP]
  67. If the OAuth 2.0 Provider supports PKCE for https://tools.ietf.org/html/rfc6749#section-2.1[Confidential Clients], you may (optionally) configure it using `DefaultOAuth2AuthorizationRequestResolver.setAuthorizationRequestCustomizer(OAuth2AuthorizationRequestCustomizers.withPkce())`.
  68. [[oauth2-client-authorization-code-redirect-uri]]
  69. [[oauth2Client-auth-code-redirect-uri]]The `DefaultOAuth2AuthorizationRequestResolver` also supports `URI` template variables for the `redirect-uri` by using `UriComponentsBuilder`.
  70. The following configuration uses all the supported `URI` template variables:
  71. [source,yaml,attrs="-attributes"]
  72. ----
  73. spring:
  74. security:
  75. oauth2:
  76. client:
  77. registration:
  78. okta:
  79. # ...
  80. redirect-uri: "{baseScheme}://{baseHost}{basePort}{basePath}/authorized/{registrationId}"
  81. # ...
  82. ----
  83. [NOTE]
  84. ====
  85. `+{baseUrl}+` resolves to `+{baseScheme}://{baseHost}{basePort}{basePath}+`
  86. ====
  87. Configuring the `redirect-uri` with `URI` template variables is especially useful when the OAuth 2.0 Client is running behind a xref:features/exploits/http.adoc#http-proxy-server[Proxy Server].
  88. Doing so ensures that the `X-Forwarded-*` headers are used when expanding the `redirect-uri`.
  89. [[oauth2-client-authorization-code-authorization-request-resolver]]
  90. === Customizing the Authorization Request
  91. One of the primary use cases an `OAuth2AuthorizationRequestResolver` can realize is the ability to customize the Authorization Request with additional parameters above the standard parameters defined in the OAuth 2.0 Authorization Framework.
  92. For example, OpenID Connect defines additional OAuth 2.0 request parameters for the https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest[Authorization Code Flow] extending from the standard parameters defined in the https://tools.ietf.org/html/rfc6749#section-4.1.1[OAuth 2.0 Authorization Framework].
  93. One of those extended parameters is the `prompt` parameter.
  94. [NOTE]
  95. ====
  96. The `prompt` parameter is optional. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for re-authentication and consent. The defined values are: `none`, `login`, `consent`, and `select_account`.
  97. ====
  98. The following example shows how to configure the `DefaultOAuth2AuthorizationRequestResolver` with a `Consumer<OAuth2AuthorizationRequest.Builder>` that customizes the Authorization Request for `oauth2Login()`, by including the request parameter `prompt=consent`.
  99. [tabs]
  100. ======
  101. Java::
  102. +
  103. [source,java,role="primary"]
  104. ----
  105. @Configuration
  106. @EnableWebSecurity
  107. public class OAuth2LoginSecurityConfig {
  108. @Autowired
  109. private ClientRegistrationRepository clientRegistrationRepository;
  110. @Bean
  111. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  112. http
  113. .authorizeHttpRequests(authorize -> authorize
  114. .anyRequest().authenticated()
  115. )
  116. .oauth2Login(oauth2 -> oauth2
  117. .authorizationEndpoint(authorization -> authorization
  118. .authorizationRequestResolver(
  119. authorizationRequestResolver(this.clientRegistrationRepository)
  120. )
  121. )
  122. );
  123. return http.build();
  124. }
  125. private OAuth2AuthorizationRequestResolver authorizationRequestResolver(
  126. ClientRegistrationRepository clientRegistrationRepository) {
  127. DefaultOAuth2AuthorizationRequestResolver authorizationRequestResolver =
  128. new DefaultOAuth2AuthorizationRequestResolver(
  129. clientRegistrationRepository, "/oauth2/authorization");
  130. authorizationRequestResolver.setAuthorizationRequestCustomizer(
  131. authorizationRequestCustomizer());
  132. return authorizationRequestResolver;
  133. }
  134. private Consumer<OAuth2AuthorizationRequest.Builder> authorizationRequestCustomizer() {
  135. return customizer -> customizer
  136. .additionalParameters(params -> params.put("prompt", "consent"));
  137. }
  138. }
  139. ----
  140. Kotlin::
  141. +
  142. [source,kotlin,role="secondary"]
  143. ----
  144. @Configuration
  145. @EnableWebSecurity
  146. class SecurityConfig {
  147. @Autowired
  148. private lateinit var customClientRegistrationRepository: ClientRegistrationRepository
  149. @Bean
  150. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  151. http {
  152. authorizeRequests {
  153. authorize(anyRequest, authenticated)
  154. }
  155. oauth2Login {
  156. authorizationEndpoint {
  157. authorizationRequestResolver = authorizationRequestResolver(customClientRegistrationRepository)
  158. }
  159. }
  160. }
  161. return http.build()
  162. }
  163. private fun authorizationRequestResolver(
  164. clientRegistrationRepository: ClientRegistrationRepository?): OAuth2AuthorizationRequestResolver {
  165. val authorizationRequestResolver = DefaultOAuth2AuthorizationRequestResolver(
  166. clientRegistrationRepository, "/oauth2/authorization")
  167. authorizationRequestResolver.setAuthorizationRequestCustomizer(
  168. authorizationRequestCustomizer())
  169. return authorizationRequestResolver
  170. }
  171. private fun authorizationRequestCustomizer(): Consumer<OAuth2AuthorizationRequest.Builder> {
  172. return Consumer { customizer ->
  173. customizer
  174. .additionalParameters { params -> params["prompt"] = "consent" }
  175. }
  176. }
  177. }
  178. ----
  179. ======
  180. For the simple use case where the additional request parameter is always the same for a specific provider, you can add it directly in the `authorization-uri` property.
  181. For example, if the value for the request parameter `prompt` is always `consent` for the provider `okta`, you can configure it as follows:
  182. [source,yaml]
  183. ----
  184. spring:
  185. security:
  186. oauth2:
  187. client:
  188. provider:
  189. okta:
  190. authorization-uri: https://dev-1234.oktapreview.com/oauth2/v1/authorize?prompt=consent
  191. ----
  192. The preceding example shows the common use case of adding a custom parameter on top of the standard parameters.
  193. Alternatively, if your requirements are more advanced, you can take full control in building the Authorization Request URI by overriding the `OAuth2AuthorizationRequest.authorizationRequestUri` property.
  194. [TIP]
  195. ====
  196. `OAuth2AuthorizationRequest.Builder.build()` constructs the `OAuth2AuthorizationRequest.authorizationRequestUri`, which represents the Authorization Request URI including all query parameters using the `application/x-www-form-urlencoded` format.
  197. ====
  198. The following example shows a variation of `authorizationRequestCustomizer()` from the preceding example and instead overrides the `OAuth2AuthorizationRequest.authorizationRequestUri` property:
  199. [tabs]
  200. ======
  201. Java::
  202. +
  203. [source,java,role="primary"]
  204. ----
  205. private Consumer<OAuth2AuthorizationRequest.Builder> authorizationRequestCustomizer() {
  206. return customizer -> customizer
  207. .authorizationRequestUri(uriBuilder -> uriBuilder
  208. .queryParam("prompt", "consent").build());
  209. }
  210. ----
  211. Kotlin::
  212. +
  213. [source,kotlin,role="secondary"]
  214. ----
  215. private fun authorizationRequestCustomizer(): Consumer<OAuth2AuthorizationRequest.Builder> {
  216. return Consumer { customizer: OAuth2AuthorizationRequest.Builder ->
  217. customizer
  218. .authorizationRequestUri { uriBuilder: UriBuilder ->
  219. uriBuilder
  220. .queryParam("prompt", "consent").build()
  221. }
  222. }
  223. }
  224. ----
  225. ======
  226. [[oauth2-client-authorization-code-authorization-request-repository]]
  227. === Storing the Authorization Request
  228. The `AuthorizationRequestRepository` is responsible for the persistence of the `OAuth2AuthorizationRequest` from the time the Authorization Request is initiated to the time the Authorization Response is received (the callback).
  229. [TIP]
  230. ====
  231. The `OAuth2AuthorizationRequest` is used to correlate and validate the Authorization Response.
  232. ====
  233. The default implementation of `AuthorizationRequestRepository` is `HttpSessionOAuth2AuthorizationRequestRepository`, which stores the `OAuth2AuthorizationRequest` in the `HttpSession`.
  234. If you have a custom implementation of `AuthorizationRequestRepository`, you can configure it as follows:
  235. .AuthorizationRequestRepository Configuration
  236. [tabs]
  237. ======
  238. Java::
  239. +
  240. [source,java,role="primary"]
  241. ----
  242. @Configuration
  243. @EnableWebSecurity
  244. public class OAuth2ClientSecurityConfig {
  245. @Bean
  246. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  247. http
  248. .oauth2Client(oauth2 -> oauth2
  249. .authorizationCodeGrant(codeGrant -> codeGrant
  250. .authorizationRequestRepository(this.authorizationRequestRepository())
  251. // ...
  252. )
  253. )
  254. .oauth2Login(oauth2 -> oauth2
  255. .authorizationEndpoint(endpoint -> endpoint
  256. .authorizationRequestRepository(this.authorizationRequestRepository())
  257. // ...
  258. )
  259. );
  260. return http.build();
  261. }
  262. @Bean
  263. public AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository() {
  264. return new CustomOAuth2AuthorizationRequestRepository();
  265. }
  266. }
  267. ----
  268. Kotlin::
  269. +
  270. [source,kotlin,role="secondary"]
  271. ----
  272. @Configuration
  273. @EnableWebSecurity
  274. class OAuth2ClientSecurityConfig {
  275. @Bean
  276. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  277. http {
  278. oauth2Client {
  279. authorizationCodeGrant {
  280. authorizationRequestRepository = authorizationRequestRepository()
  281. }
  282. }
  283. }
  284. return http.build()
  285. }
  286. }
  287. ----
  288. Xml::
  289. +
  290. [source,xml,role="secondary"]
  291. ----
  292. <http>
  293. <oauth2-client>
  294. <authorization-code-grant authorization-request-repository-ref="authorizationRequestRepository"/>
  295. </oauth2-client>
  296. </http>
  297. ----
  298. ======
  299. [[oauth2-client-authorization-code-access-token]]
  300. === Requesting an Access Token
  301. [NOTE]
  302. ====
  303. See the https://tools.ietf.org/html/rfc6749#section-4.1.3[Access Token Request/Response] protocol flow for the Authorization Code grant.
  304. ====
  305. There are two implementations of `OAuth2AccessTokenResponseClient` that can be used to make HTTP requests to the Token Endpoint in order to obtain an access token for the Authorization Code grant:
  306. * `DefaultAuthorizationCodeTokenResponseClient` (_default_)
  307. * `RestClientAuthorizationCodeTokenResponseClient`
  308. The default implementation uses a `RestOperations` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
  309. Spring Security 6.4 introduces a new implementation based on `RestClient`, which provides similar functionality but is better aligned with the Reactive version of the component (based on `WebClient`) in order to provide consistent configuration for applications on either stack.
  310. [NOTE]
  311. ====
  312. This section focuses on `RestClientAuthorizationCodeTokenResponseClient`.
  313. You can read about {spring-security-reference-base-url}/6.3/servlet/oauth2/client/authorization-grants.html#_requesting_an_access_token[`DefaultAuthorizationCodeTokenResponseClient`] in the Spring Security 6.3 documentation.
  314. ====
  315. :section-id: authorization-code
  316. :grant-type: Authorization Code
  317. :class-name: RestClientAuthorizationCodeTokenResponseClient
  318. :grant-request: OAuth2AuthorizationCodeGrantRequest
  319. :leveloffset: +1
  320. include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
  321. :leveloffset: -1
  322. [[oauth2-client-authorization-code-access-token-response-client-dsl]]
  323. === Customize using the DSL
  324. Whether you customize `{class-name}` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you can configure it using the DSL (as an alternative to <<oauth2-client-authorization-code-access-token-response-client-bean,publishing a bean>>) as follows:
  325. .Access Token Response Configuration via DSL
  326. [tabs]
  327. ======
  328. Java::
  329. +
  330. [source,java,role="primary"]
  331. ----
  332. @Configuration
  333. @EnableWebSecurity
  334. public class OAuth2ClientSecurityConfig {
  335. @Bean
  336. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  337. http
  338. .oauth2Client(oauth2 -> oauth2
  339. .authorizationCodeGrant(codeGrant -> codeGrant
  340. .accessTokenResponseClient(this.accessTokenResponseClient())
  341. // ...
  342. )
  343. );
  344. return http.build();
  345. }
  346. }
  347. ----
  348. Kotlin::
  349. +
  350. [source,kotlin,role="secondary"]
  351. ----
  352. @Configuration
  353. @EnableWebSecurity
  354. class OAuth2ClientSecurityConfig {
  355. @Bean
  356. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  357. http {
  358. oauth2Client {
  359. authorizationCodeGrant {
  360. accessTokenResponseClient = accessTokenResponseClient()
  361. }
  362. }
  363. }
  364. return http.build()
  365. }
  366. }
  367. ----
  368. Xml::
  369. +
  370. [source,xml,role="secondary"]
  371. ----
  372. <http>
  373. <oauth2-client>
  374. <authorization-code-grant access-token-response-client-ref="accessTokenResponseClient"/>
  375. </oauth2-client>
  376. </http>
  377. ----
  378. ======
  379. [[oauth2-client-refresh-token]]
  380. == [[oauth2Client-refresh-token-grant]]Refresh Token
  381. [NOTE]
  382. ====
  383. See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.5[Refresh Token].
  384. ====
  385. [[oauth2-client-refresh-token-access-token]]
  386. === Refreshing an Access Token
  387. [NOTE]
  388. ====
  389. See the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant.
  390. ====
  391. There are two implementations of `OAuth2AccessTokenResponseClient` that can be used to make HTTP requests to the Token Endpoint in order to obtain an access token for the Refresh Token grant:
  392. * `DefaultRefreshTokenTokenResponseClient` (_default_)
  393. * `RestClientRefreshTokenTokenResponseClient`
  394. The default implementation uses a `RestOperations` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
  395. Spring Security 6.4 introduces a new implementation based on `RestClient`, which provides similar functionality but is better aligned with the Reactive version of the component (based on `WebClient`) in order to provide consistent configuration for applications on either stack.
  396. [NOTE]
  397. ====
  398. This section focuses on `RestClientRefreshTokenTokenResponseClient`.
  399. You can read about {spring-security-reference-base-url}/6.3/servlet/oauth2/client/authorization-grants.html#_refreshing_an_access_token[`DefaultRefreshTokenTokenResponseClient`] in the Spring Security 6.3 documentation.
  400. ====
  401. :section-id: refresh-token
  402. :grant-type: Refresh Token
  403. :class-name: RestClientRefreshTokenTokenResponseClient
  404. :grant-request: OAuth2RefreshTokenGrantRequest
  405. :leveloffset: +1
  406. include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
  407. :leveloffset: -1
  408. [[oauth2-client-refresh-token-authorized-client-provider-builder]]
  409. === Customize using the Builder
  410. Whether you customize `RestClientRefreshTokenTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you can configure it using the `OAuth2AuthorizedClientProviderBuilder` (as an alternative to <<oauth2-client-refresh-token-access-token-response-client-bean,publishing a bean>>) as follows:
  411. [tabs]
  412. ======
  413. Java::
  414. +
  415. [source,java,role="primary"]
  416. ----
  417. // Customize
  418. OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenTokenResponseClient = ...
  419. OAuth2AuthorizedClientProvider authorizedClientProvider =
  420. OAuth2AuthorizedClientProviderBuilder.builder()
  421. .authorizationCode()
  422. .refreshToken(configurer -> configurer.accessTokenResponseClient(refreshTokenTokenResponseClient))
  423. .build();
  424. // ...
  425. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  426. ----
  427. Kotlin::
  428. +
  429. [source,kotlin,role="secondary"]
  430. ----
  431. // Customize
  432. val refreshTokenTokenResponseClient: OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> = ...
  433. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  434. .authorizationCode()
  435. .refreshToken { it.accessTokenResponseClient(refreshTokenTokenResponseClient) }
  436. .build()
  437. // ...
  438. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  439. ----
  440. ======
  441. [NOTE]
  442. ====
  443. `OAuth2AuthorizedClientProviderBuilder.builder().refreshToken()` configures a `RefreshTokenOAuth2AuthorizedClientProvider`,
  444. which is an implementation of an `OAuth2AuthorizedClientProvider` for the Refresh Token grant.
  445. ====
  446. The `OAuth2RefreshToken` can optionally be returned in the Access Token Response for the `authorization_code` and `password` grant types.
  447. If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2AuthorizedClient.getAccessToken()` is expired, it is automatically refreshed by the `RefreshTokenOAuth2AuthorizedClientProvider`.
  448. [[oauth2-client-client-credentials]]
  449. == [[oauth2Client-client-creds-grant]]Client Credentials
  450. [NOTE]
  451. ====
  452. Please refer to the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials] grant.
  453. ====
  454. [[oauth2-client-client-credentials-access-token]]
  455. === Requesting an Access Token
  456. [NOTE]
  457. ====
  458. See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials] grant.
  459. ====
  460. There are two implementations of `OAuth2AccessTokenResponseClient` that can be used to make HTTP requests to the Token Endpoint in order to obtain an access token for the Client Credentials grant:
  461. * `DefaultClientCredentialsTokenResponseClient` (_default_)
  462. * `RestClientClientCredentialsTokenResponseClient`
  463. The default implementation uses a `RestOperations` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
  464. Spring Security 6.4 introduces a new implementation based on `RestClient`, which provides similar functionality but is better aligned with the Reactive version of the component (based on `WebClient`) in order to provide consistent configuration for applications on either stack.
  465. [NOTE]
  466. ====
  467. This section focuses on `RestClientClientCredentialsTokenResponseClient`.
  468. You can read about {spring-security-reference-base-url}/6.3/servlet/oauth2/client/authorization-grants.html#_requesting_an_access_token_2[`DefaultClientCredentialsTokenResponseClient`] in the Spring Security 6.3 documentation.
  469. ====
  470. :section-id: client-credentials
  471. :grant-type: Client Credentials
  472. :class-name: RestClientClientCredentialsTokenResponseClient
  473. :grant-request: OAuth2ClientCredentialsGrantRequest
  474. :leveloffset: +1
  475. include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
  476. :leveloffset: -1
  477. [[oauth2-client-client-credentials-authorized-client-provider-builder]]
  478. === Customize using the Builder
  479. Whether you customize `RestClientClientCredentialsTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you can configure it using the `OAuth2AuthorizedClientProviderBuilder` (as an alternative to <<oauth2-client-client-credentials-access-token-response-client-bean,publishing a bean>>) as follows:
  480. [tabs]
  481. ======
  482. Java::
  483. +
  484. [source,java,role="primary"]
  485. ----
  486. // Customize
  487. OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsTokenResponseClient = ...
  488. OAuth2AuthorizedClientProvider authorizedClientProvider =
  489. OAuth2AuthorizedClientProviderBuilder.builder()
  490. .clientCredentials(configurer -> configurer.accessTokenResponseClient(clientCredentialsTokenResponseClient))
  491. .build();
  492. // ...
  493. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  494. ----
  495. Kotlin::
  496. +
  497. [source,kotlin,role="secondary"]
  498. ----
  499. // Customize
  500. val clientCredentialsTokenResponseClient: OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> = ...
  501. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  502. .clientCredentials { it.accessTokenResponseClient(clientCredentialsTokenResponseClient) }
  503. .build()
  504. // ...
  505. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  506. ----
  507. ======
  508. [NOTE]
  509. ====
  510. `OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials()` configures a `ClientCredentialsOAuth2AuthorizedClientProvider`,
  511. which is an implementation of an `OAuth2AuthorizedClientProvider` for the Client Credentials grant.
  512. ====
  513. [[oauth2-client-client-credentials-authorized-client-manager]]
  514. === Using the Access Token
  515. Consider the following Spring Boot properties for an OAuth 2.0 Client registration:
  516. [source,yaml]
  517. ----
  518. spring:
  519. security:
  520. oauth2:
  521. client:
  522. registration:
  523. okta:
  524. client-id: okta-client-id
  525. client-secret: okta-client-secret
  526. authorization-grant-type: client_credentials
  527. scope: read, write
  528. provider:
  529. okta:
  530. token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
  531. ----
  532. Further consider the following `OAuth2AuthorizedClientManager` `@Bean`:
  533. [tabs]
  534. ======
  535. Java::
  536. +
  537. [source,java,role="primary"]
  538. ----
  539. @Bean
  540. public OAuth2AuthorizedClientManager authorizedClientManager(
  541. ClientRegistrationRepository clientRegistrationRepository,
  542. OAuth2AuthorizedClientRepository authorizedClientRepository) {
  543. OAuth2AuthorizedClientProvider authorizedClientProvider =
  544. OAuth2AuthorizedClientProviderBuilder.builder()
  545. .clientCredentials()
  546. .build();
  547. DefaultOAuth2AuthorizedClientManager authorizedClientManager =
  548. new DefaultOAuth2AuthorizedClientManager(
  549. clientRegistrationRepository, authorizedClientRepository);
  550. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  551. return authorizedClientManager;
  552. }
  553. ----
  554. Kotlin::
  555. +
  556. [source,kotlin,role="secondary"]
  557. ----
  558. @Bean
  559. fun authorizedClientManager(
  560. clientRegistrationRepository: ClientRegistrationRepository,
  561. authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
  562. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  563. .clientCredentials()
  564. .build()
  565. val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
  566. clientRegistrationRepository, authorizedClientRepository)
  567. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  568. return authorizedClientManager
  569. }
  570. ----
  571. ======
  572. Given the preceding properties and bean, you can obtain the `OAuth2AccessToken` as follows:
  573. [tabs]
  574. ======
  575. Java::
  576. +
  577. [source,java,role="primary"]
  578. ----
  579. @Controller
  580. public class OAuth2ClientController {
  581. @Autowired
  582. private OAuth2AuthorizedClientManager authorizedClientManager;
  583. @GetMapping("/")
  584. public String index(Authentication authentication,
  585. HttpServletRequest servletRequest,
  586. HttpServletResponse servletResponse) {
  587. OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  588. .principal(authentication)
  589. .attributes(attrs -> {
  590. attrs.put(HttpServletRequest.class.getName(), servletRequest);
  591. attrs.put(HttpServletResponse.class.getName(), servletResponse);
  592. })
  593. .build();
  594. OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
  595. OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
  596. // ...
  597. return "index";
  598. }
  599. }
  600. ----
  601. Kotlin::
  602. +
  603. [source,kotlin,role="secondary"]
  604. ----
  605. class OAuth2ClientController {
  606. @Autowired
  607. private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
  608. @GetMapping("/")
  609. fun index(authentication: Authentication?,
  610. servletRequest: HttpServletRequest,
  611. servletResponse: HttpServletResponse): String {
  612. val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  613. .principal(authentication)
  614. .attributes(Consumer { attrs: MutableMap<String, Any> ->
  615. attrs[HttpServletRequest::class.java.name] = servletRequest
  616. attrs[HttpServletResponse::class.java.name] = servletResponse
  617. })
  618. .build()
  619. val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
  620. val accessToken: OAuth2AccessToken = authorizedClient.accessToken
  621. // ...
  622. return "index"
  623. }
  624. }
  625. ----
  626. ======
  627. [NOTE]
  628. ====
  629. `HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes.
  630. If not provided, they default to `ServletRequestAttributes` by using `RequestContextHolder.getRequestAttributes()`.
  631. ====
  632. [[oauth2-client-password]]
  633. == [[oauth2Client-password-grant]]Resource Owner Password Credentials
  634. [NOTE]
  635. ====
  636. See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials] grant.
  637. ====
  638. [[oauth2-client-password-access-token]]
  639. === Requesting an Access Token
  640. [NOTE]
  641. ====
  642. See the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/Response] protocol flow for the Resource Owner Password Credentials grant.
  643. ====
  644. The default implementation of `OAuth2AccessTokenResponseClient` for the Resource Owner Password Credentials grant is `DefaultPasswordTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint.
  645. [CAUTION]
  646. ====
  647. The `DefaultPasswordTokenResponseClient` class and support for the Resource Owner Password Credentials grant are deprecated.
  648. This section will be removed in Spring Security 7.
  649. ====
  650. The `DefaultPasswordTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response.
  651. [[oauth2-client-password-access-token-request]]
  652. === Customizing the Access Token Request
  653. If you need to customize the pre-processing of the Token Request, you can provide `DefaultPasswordTokenResponseClient.setRequestEntityConverter()` with a custom `Converter<OAuth2PasswordGrantRequest, RequestEntity<?>>`.
  654. The default implementation (`OAuth2PasswordGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.3.2[OAuth 2.0 Access Token Request].
  655. However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s).
  656. To customize only the parameters of the request, you can provide `OAuth2PasswordGrantRequestEntityConverter.setParametersConverter()` with a custom `Converter<OAuth2PasswordGrantRequest, MultiValueMap<String, String>>` to completely override the parameters sent with the request. This is often simpler than constructing a `RequestEntity` directly.
  657. [TIP]
  658. ====
  659. If you prefer to only add additional parameters, you can provide `OAuth2PasswordGrantRequestEntityConverter.addParametersConverter()` with a custom `Converter<OAuth2PasswordGrantRequest, MultiValueMap<String, String>>` which constructs an aggregate `Converter`.
  660. ====
  661. [IMPORTANT]
  662. ====
  663. The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider.
  664. ====
  665. [[oauth2-client-password-access-token-response]]
  666. === Customizing the Access Token Response
  667. On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultPasswordTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`.
  668. The default `RestOperations` is configured as follows:
  669. [tabs]
  670. ======
  671. Java::
  672. +
  673. [source,java,role="primary"]
  674. ----
  675. RestTemplate restTemplate = new RestTemplate(Arrays.asList(
  676. new FormHttpMessageConverter(),
  677. new OAuth2AccessTokenResponseHttpMessageConverter()));
  678. restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
  679. ----
  680. Kotlin::
  681. +
  682. [source,kotlin,role="secondary"]
  683. ----
  684. val restTemplate = RestTemplate(listOf(
  685. FormHttpMessageConverter(),
  686. OAuth2AccessTokenResponseHttpMessageConverter()))
  687. restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler()
  688. ----
  689. ======
  690. [TIP]
  691. ====
  692. Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request.
  693. ====
  694. `OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response.
  695. You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter<Map<String, String>, OAuth2AccessTokenResponse>` that is used to convert the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`.
  696. `OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`.
  697. It uses an `OAuth2ErrorHttpMessageConverter` to convert the OAuth 2.0 Error parameters to an `OAuth2Error`.
  698. [[oauth2-client-password-authorized-client-provider-builder]]
  699. === Customize using the Builder
  700. Whether you customize `DefaultPasswordTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows:
  701. [tabs]
  702. ======
  703. Java::
  704. +
  705. [source,java,role="primary"]
  706. ----
  707. // Customize
  708. OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordTokenResponseClient = ...
  709. OAuth2AuthorizedClientProvider authorizedClientProvider =
  710. OAuth2AuthorizedClientProviderBuilder.builder()
  711. .password(configurer -> configurer.accessTokenResponseClient(passwordTokenResponseClient))
  712. .refreshToken()
  713. .build();
  714. // ...
  715. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  716. ----
  717. Kotlin::
  718. +
  719. [source,kotlin,role="secondary"]
  720. ----
  721. val passwordTokenResponseClient: OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> = ...
  722. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  723. .password { it.accessTokenResponseClient(passwordTokenResponseClient) }
  724. .refreshToken()
  725. .build()
  726. // ...
  727. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  728. ----
  729. ======
  730. [NOTE]
  731. ====
  732. `OAuth2AuthorizedClientProviderBuilder.builder().password()` configures a `PasswordOAuth2AuthorizedClientProvider`,
  733. which is an implementation of an `OAuth2AuthorizedClientProvider` for the Resource Owner Password Credentials grant.
  734. ====
  735. [[oauth2-client-password-authorized-client-manager]]
  736. === Using the Access Token
  737. Consider the following Spring Boot properties for an OAuth 2.0 Client registration:
  738. [source,yaml]
  739. ----
  740. spring:
  741. security:
  742. oauth2:
  743. client:
  744. registration:
  745. okta:
  746. client-id: okta-client-id
  747. client-secret: okta-client-secret
  748. authorization-grant-type: password
  749. scope: read, write
  750. provider:
  751. okta:
  752. token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
  753. ----
  754. Further consider the `OAuth2AuthorizedClientManager` `@Bean`:
  755. [tabs]
  756. ======
  757. Java::
  758. +
  759. [source,java,role="primary"]
  760. ----
  761. @Bean
  762. public OAuth2AuthorizedClientManager authorizedClientManager(
  763. ClientRegistrationRepository clientRegistrationRepository,
  764. OAuth2AuthorizedClientRepository authorizedClientRepository) {
  765. OAuth2AuthorizedClientProvider authorizedClientProvider =
  766. OAuth2AuthorizedClientProviderBuilder.builder()
  767. .password()
  768. .refreshToken()
  769. .build();
  770. DefaultOAuth2AuthorizedClientManager authorizedClientManager =
  771. new DefaultOAuth2AuthorizedClientManager(
  772. clientRegistrationRepository, authorizedClientRepository);
  773. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  774. // Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
  775. // map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
  776. authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());
  777. return authorizedClientManager;
  778. }
  779. private Function<OAuth2AuthorizeRequest, Map<String, Object>> contextAttributesMapper() {
  780. return authorizeRequest -> {
  781. Map<String, Object> contextAttributes = Collections.emptyMap();
  782. HttpServletRequest servletRequest = authorizeRequest.getAttribute(HttpServletRequest.class.getName());
  783. String username = servletRequest.getParameter(OAuth2ParameterNames.USERNAME);
  784. String password = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD);
  785. if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
  786. contextAttributes = new HashMap<>();
  787. // `PasswordOAuth2AuthorizedClientProvider` requires both attributes
  788. contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, username);
  789. contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, password);
  790. }
  791. return contextAttributes;
  792. };
  793. }
  794. ----
  795. Kotlin::
  796. +
  797. [source,kotlin,role="secondary"]
  798. ----
  799. @Bean
  800. fun authorizedClientManager(
  801. clientRegistrationRepository: ClientRegistrationRepository,
  802. authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
  803. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  804. .password()
  805. .refreshToken()
  806. .build()
  807. val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
  808. clientRegistrationRepository, authorizedClientRepository)
  809. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  810. // Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
  811. // map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
  812. authorizedClientManager.setContextAttributesMapper(contextAttributesMapper())
  813. return authorizedClientManager
  814. }
  815. private fun contextAttributesMapper(): Function<OAuth2AuthorizeRequest, MutableMap<String, Any>> {
  816. return Function { authorizeRequest ->
  817. var contextAttributes: MutableMap<String, Any> = mutableMapOf()
  818. val servletRequest: HttpServletRequest = authorizeRequest.getAttribute(HttpServletRequest::class.java.name)
  819. val username = servletRequest.getParameter(OAuth2ParameterNames.USERNAME)
  820. val password = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD)
  821. if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
  822. contextAttributes = hashMapOf()
  823. // `PasswordOAuth2AuthorizedClientProvider` requires both attributes
  824. contextAttributes[OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME] = username
  825. contextAttributes[OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME] = password
  826. }
  827. contextAttributes
  828. }
  829. }
  830. ----
  831. ======
  832. Given the preceding properties and bean, you can obtain the `OAuth2AccessToken` as follows:
  833. [tabs]
  834. ======
  835. Java::
  836. +
  837. [source,java,role="primary"]
  838. ----
  839. @Controller
  840. public class OAuth2ClientController {
  841. @Autowired
  842. private OAuth2AuthorizedClientManager authorizedClientManager;
  843. @GetMapping("/")
  844. public String index(Authentication authentication,
  845. HttpServletRequest servletRequest,
  846. HttpServletResponse servletResponse) {
  847. OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  848. .principal(authentication)
  849. .attributes(attrs -> {
  850. attrs.put(HttpServletRequest.class.getName(), servletRequest);
  851. attrs.put(HttpServletResponse.class.getName(), servletResponse);
  852. })
  853. .build();
  854. OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
  855. OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
  856. // ...
  857. return "index";
  858. }
  859. }
  860. ----
  861. Kotlin::
  862. +
  863. [source,kotlin,role="secondary"]
  864. ----
  865. @Controller
  866. class OAuth2ClientController {
  867. @Autowired
  868. private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
  869. @GetMapping("/")
  870. fun index(authentication: Authentication?,
  871. servletRequest: HttpServletRequest,
  872. servletResponse: HttpServletResponse): String {
  873. val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  874. .principal(authentication)
  875. .attributes(Consumer {
  876. it[HttpServletRequest::class.java.name] = servletRequest
  877. it[HttpServletResponse::class.java.name] = servletResponse
  878. })
  879. .build()
  880. val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
  881. val accessToken: OAuth2AccessToken = authorizedClient.accessToken
  882. // ...
  883. return "index"
  884. }
  885. }
  886. ----
  887. ======
  888. [NOTE]
  889. ====
  890. `HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes.
  891. If not provided, they default to `ServletRequestAttributes` using `RequestContextHolder.getRequestAttributes()`.
  892. ====
  893. [[oauth2-client-jwt-bearer]]
  894. == [[oauth2Client-jwt-bearer-grant]]JWT Bearer
  895. [NOTE]
  896. ====
  897. Please refer to JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants for further details on the https://datatracker.ietf.org/doc/html/rfc7523[JWT Bearer] grant.
  898. ====
  899. [[oauth2-client-jwt-bearer-access-token]]
  900. === Requesting an Access Token
  901. [NOTE]
  902. ====
  903. Please refer to the https://datatracker.ietf.org/doc/html/rfc7523#section-2.1[Access Token Request/Response] protocol flow for the JWT Bearer grant.
  904. ====
  905. There are two implementations of `OAuth2AccessTokenResponseClient` that can be used to make HTTP requests to the Token Endpoint in order to obtain an access token for the JWT Bearer grant:
  906. * `DefaultJwtBearerTokenResponseClient` (_default_)
  907. * `RestClientJwtBearerTokenResponseClient`
  908. The default implementation uses a `RestOperations` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
  909. Spring Security 6.4 introduces a new implementation based on `RestClient`, which provides similar functionality but is better aligned with the Reactive version of the component (based on `WebClient`) in order to provide consistent configuration for applications on either stack.
  910. [NOTE]
  911. ====
  912. This section focuses on `RestClientJwtBearerTokenResponseClient`.
  913. You can read about {spring-security-reference-base-url}/6.3/servlet/oauth2/client/authorization-grants.html#_requesting_an_access_token_4[`DefaultClientCredentialsTokenResponseClient`] in the Spring Security 6.3 documentation.
  914. ====
  915. :section-id: jwt-bearer
  916. :grant-type: JWT Bearer
  917. :class-name: RestClientJwtBearerTokenResponseClient
  918. :grant-request: JwtBearerGrantRequest
  919. :leveloffset: +1
  920. include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
  921. :leveloffset: -1
  922. [[oauth2-client-jwt-bearer-authorized-client-provider-builder]]
  923. === Customize using the Builder
  924. Whether you customize `RestClientJwtBearerTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you can configure it using the `OAuth2AuthorizedClientProviderBuilder` (as an alternative to <<oauth2-client-jwt-bearer-access-token-response-client-bean,publishing a bean>>) as follows:
  925. [tabs]
  926. ======
  927. Java::
  928. +
  929. [source,java,role="primary"]
  930. ----
  931. // Customize
  932. OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerTokenResponseClient = ...
  933. JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider = new JwtBearerOAuth2AuthorizedClientProvider();
  934. jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerTokenResponseClient);
  935. OAuth2AuthorizedClientProvider authorizedClientProvider =
  936. OAuth2AuthorizedClientProviderBuilder.builder()
  937. .provider(jwtBearerAuthorizedClientProvider)
  938. .build();
  939. // ...
  940. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  941. ----
  942. Kotlin::
  943. +
  944. [source,kotlin,role="secondary"]
  945. ----
  946. // Customize
  947. val jwtBearerTokenResponseClient: OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> = ...
  948. val jwtBearerAuthorizedClientProvider = JwtBearerOAuth2AuthorizedClientProvider()
  949. jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerTokenResponseClient)
  950. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  951. .provider(jwtBearerAuthorizedClientProvider)
  952. .build()
  953. // ...
  954. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  955. ----
  956. ======
  957. [[oauth2-client-jwt-bearer-authorized-client-manager]]
  958. === Using the Access Token
  959. Given the following Spring Boot properties for an OAuth 2.0 Client registration:
  960. [source,yaml]
  961. ----
  962. spring:
  963. security:
  964. oauth2:
  965. client:
  966. registration:
  967. okta:
  968. client-id: okta-client-id
  969. client-secret: okta-client-secret
  970. authorization-grant-type: urn:ietf:params:oauth:grant-type:jwt-bearer
  971. scope: read
  972. provider:
  973. okta:
  974. token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
  975. ----
  976. ...and the `OAuth2AuthorizedClientManager` `@Bean`:
  977. [tabs]
  978. ======
  979. Java::
  980. +
  981. [source,java,role="primary"]
  982. ----
  983. @Bean
  984. public OAuth2AuthorizedClientManager authorizedClientManager(
  985. ClientRegistrationRepository clientRegistrationRepository,
  986. OAuth2AuthorizedClientRepository authorizedClientRepository) {
  987. JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider =
  988. new JwtBearerOAuth2AuthorizedClientProvider();
  989. OAuth2AuthorizedClientProvider authorizedClientProvider =
  990. OAuth2AuthorizedClientProviderBuilder.builder()
  991. .provider(jwtBearerAuthorizedClientProvider)
  992. .build();
  993. DefaultOAuth2AuthorizedClientManager authorizedClientManager =
  994. new DefaultOAuth2AuthorizedClientManager(
  995. clientRegistrationRepository, authorizedClientRepository);
  996. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  997. return authorizedClientManager;
  998. }
  999. ----
  1000. Kotlin::
  1001. +
  1002. [source,kotlin,role="secondary"]
  1003. ----
  1004. @Bean
  1005. fun authorizedClientManager(
  1006. clientRegistrationRepository: ClientRegistrationRepository,
  1007. authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
  1008. val jwtBearerAuthorizedClientProvider = JwtBearerOAuth2AuthorizedClientProvider()
  1009. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  1010. .provider(jwtBearerAuthorizedClientProvider)
  1011. .build()
  1012. val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
  1013. clientRegistrationRepository, authorizedClientRepository)
  1014. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  1015. return authorizedClientManager
  1016. }
  1017. ----
  1018. ======
  1019. You may obtain the `OAuth2AccessToken` as follows:
  1020. [tabs]
  1021. ======
  1022. Java::
  1023. +
  1024. [source,java,role="primary"]
  1025. ----
  1026. @RestController
  1027. public class OAuth2ResourceServerController {
  1028. @Autowired
  1029. private OAuth2AuthorizedClientManager authorizedClientManager;
  1030. @GetMapping("/resource")
  1031. public String resource(JwtAuthenticationToken jwtAuthentication) {
  1032. OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  1033. .principal(jwtAuthentication)
  1034. .build();
  1035. OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
  1036. OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
  1037. // ...
  1038. }
  1039. }
  1040. ----
  1041. Kotlin::
  1042. +
  1043. [source,kotlin,role="secondary"]
  1044. ----
  1045. class OAuth2ResourceServerController {
  1046. @Autowired
  1047. private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
  1048. @GetMapping("/resource")
  1049. fun resource(jwtAuthentication: JwtAuthenticationToken?): String {
  1050. val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  1051. .principal(jwtAuthentication)
  1052. .build()
  1053. val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
  1054. val accessToken: OAuth2AccessToken = authorizedClient.accessToken
  1055. // ...
  1056. }
  1057. }
  1058. ----
  1059. ======
  1060. [NOTE]
  1061. `JwtBearerOAuth2AuthorizedClientProvider` resolves the `Jwt` assertion via `OAuth2AuthorizationContext.getPrincipal().getPrincipal()` by default, hence the use of `JwtAuthenticationToken` in the preceding example.
  1062. [TIP]
  1063. If you need to resolve the `Jwt` assertion from a different source, you can provide `JwtBearerOAuth2AuthorizedClientProvider.setJwtAssertionResolver()` with a custom `Function<OAuth2AuthorizationContext, Jwt>`.
  1064. [[oauth2-client-token-exchange]]
  1065. == [[oauth2Client-token-exchange-grant]]Token Exchange
  1066. [NOTE]
  1067. ====
  1068. Please refer to OAuth 2.0 Token Exchange for further details on the https://datatracker.ietf.org/doc/html/rfc8693[Token Exchange] grant.
  1069. ====
  1070. [[oauth2-client-token-exchange-access-token]]
  1071. === Requesting an Access Token
  1072. [NOTE]
  1073. ====
  1074. Please refer to the https://datatracker.ietf.org/doc/html/rfc8693#section-2[Token Exchange Request and Response] protocol flow for the Token Exchange grant.
  1075. ====
  1076. There are two implementations of `OAuth2AccessTokenResponseClient` that can be used to make HTTP requests to the Token Endpoint in order to obtain an access token for the Token Exchange grant:
  1077. * `DefaultTokenExchangeTokenResponseClient` (_default_)
  1078. * `RestClientTokenExchangeTokenResponseClient`
  1079. The default implementation uses a `RestOperations` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
  1080. Spring Security 6.4 introduces a new implementation based on `RestClient`, which provides similar functionality but is better aligned with the Reactive version of the component (based on `WebClient`) in order to provide consistent configuration for applications on either stack.
  1081. [NOTE]
  1082. ====
  1083. This section focuses on `RestClientTokenExchangeTokenResponseClient`.
  1084. You can read about {spring-security-reference-base-url}/6.3/servlet/oauth2/client/authorization-grants.html#_requesting_an_access_token_5[`DefaultTokenExchangeTokenResponseClient`] in the Spring Security 6.3 documentation.
  1085. ====
  1086. :section-id: token-exchange
  1087. :grant-type: Token Exchange
  1088. :class-name: RestClientTokenExchangeTokenResponseClient
  1089. :grant-request: TokenExchangeGrantRequest
  1090. :leveloffset: +1
  1091. include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
  1092. :leveloffset: -1
  1093. [[oauth2-client-token-exchange-authorized-client-provider-builder]]
  1094. === Customize using the Builder
  1095. Whether you customize `RestClientTokenExchangeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you can configure it using the `OAuth2AuthorizedClientProviderBuilder` (as an alternative to <<oauth2-client-token-exchange-access-token-response-client-bean,publishing a bean>>) as follows:
  1096. [tabs]
  1097. ======
  1098. Java::
  1099. +
  1100. [source,java,role="primary"]
  1101. ----
  1102. // Customize
  1103. OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeTokenResponseClient = ...
  1104. TokenExchangeOAuth2AuthorizedClientProvider tokenExchangeAuthorizedClientProvider = new TokenExchangeOAuth2AuthorizedClientProvider();
  1105. tokenExchangeAuthorizedClientProvider.setAccessTokenResponseClient(tokenExchangeTokenResponseClient);
  1106. OAuth2AuthorizedClientProvider authorizedClientProvider =
  1107. OAuth2AuthorizedClientProviderBuilder.builder()
  1108. .provider(tokenExchangeAuthorizedClientProvider)
  1109. .build();
  1110. // ...
  1111. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  1112. ----
  1113. Kotlin::
  1114. +
  1115. [source,kotlin,role="secondary"]
  1116. ----
  1117. // Customize
  1118. val tokenExchangeTokenResponseClient: OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> = ...
  1119. val tokenExchangeAuthorizedClientProvider = TokenExchangeOAuth2AuthorizedClientProvider()
  1120. tokenExchangeAuthorizedClientProvider.setAccessTokenResponseClient(tokenExchangeTokenResponseClient)
  1121. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  1122. .provider(tokenExchangeAuthorizedClientProvider)
  1123. .build()
  1124. // ...
  1125. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  1126. ----
  1127. ======
  1128. [[oauth2-client-token-exchange-authorized-client-manager]]
  1129. === [[token-exchange-grant-access-token]]Using the Access Token
  1130. Given the following Spring Boot properties for an OAuth 2.0 Client registration:
  1131. [source,yaml]
  1132. ----
  1133. spring:
  1134. security:
  1135. oauth2:
  1136. client:
  1137. registration:
  1138. okta:
  1139. client-id: okta-client-id
  1140. client-secret: okta-client-secret
  1141. authorization-grant-type: urn:ietf:params:oauth:grant-type:token-exchange
  1142. scope: read
  1143. provider:
  1144. okta:
  1145. token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
  1146. ----
  1147. ...and the `OAuth2AuthorizedClientManager` `@Bean`:
  1148. [tabs]
  1149. ======
  1150. Java::
  1151. +
  1152. [source,java,role="primary"]
  1153. ----
  1154. @Bean
  1155. public OAuth2AuthorizedClientManager authorizedClientManager(
  1156. ClientRegistrationRepository clientRegistrationRepository,
  1157. OAuth2AuthorizedClientRepository authorizedClientRepository) {
  1158. TokenExchangeOAuth2AuthorizedClientProvider tokenExchangeAuthorizedClientProvider =
  1159. new TokenExchangeOAuth2AuthorizedClientProvider();
  1160. OAuth2AuthorizedClientProvider authorizedClientProvider =
  1161. OAuth2AuthorizedClientProviderBuilder.builder()
  1162. .provider(tokenExchangeAuthorizedClientProvider)
  1163. .build();
  1164. DefaultOAuth2AuthorizedClientManager authorizedClientManager =
  1165. new DefaultOAuth2AuthorizedClientManager(
  1166. clientRegistrationRepository, authorizedClientRepository);
  1167. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  1168. return authorizedClientManager;
  1169. }
  1170. ----
  1171. Kotlin::
  1172. +
  1173. [source,kotlin,role="secondary"]
  1174. ----
  1175. @Bean
  1176. fun authorizedClientManager(
  1177. clientRegistrationRepository: ClientRegistrationRepository,
  1178. authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
  1179. val tokenExchangeAuthorizedClientProvider = TokenExchangeOAuth2AuthorizedClientProvider()
  1180. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  1181. .provider(tokenExchangeAuthorizedClientProvider)
  1182. .build()
  1183. val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
  1184. clientRegistrationRepository, authorizedClientRepository)
  1185. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  1186. return authorizedClientManager
  1187. }
  1188. ----
  1189. ======
  1190. You may obtain the `OAuth2AccessToken` as follows:
  1191. [tabs]
  1192. ======
  1193. Java::
  1194. +
  1195. [source,java,role="primary"]
  1196. ----
  1197. @RestController
  1198. public class OAuth2ResourceServerController {
  1199. @Autowired
  1200. private OAuth2AuthorizedClientManager authorizedClientManager;
  1201. @GetMapping("/resource")
  1202. public String resource(JwtAuthenticationToken jwtAuthentication) {
  1203. OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  1204. .principal(jwtAuthentication)
  1205. .build();
  1206. OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
  1207. OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
  1208. // ...
  1209. }
  1210. }
  1211. ----
  1212. Kotlin::
  1213. +
  1214. [source,kotlin,role="secondary"]
  1215. ----
  1216. class OAuth2ResourceServerController {
  1217. @Autowired
  1218. private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
  1219. @GetMapping("/resource")
  1220. fun resource(jwtAuthentication: JwtAuthenticationToken?): String {
  1221. val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  1222. .principal(jwtAuthentication)
  1223. .build()
  1224. val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
  1225. val accessToken: OAuth2AccessToken = authorizedClient.accessToken
  1226. // ...
  1227. }
  1228. }
  1229. ----
  1230. ======
  1231. [NOTE]
  1232. `TokenExchangeOAuth2AuthorizedClientProvider` resolves the subject token (as an `OAuth2Token`) via `OAuth2AuthorizationContext.getPrincipal().getPrincipal()` by default, hence the use of `JwtAuthenticationToken` in the preceding example.
  1233. An actor token is not resolved by default.
  1234. [TIP]
  1235. If you need to resolve the subject token from a different source, you can provide `TokenExchangeOAuth2AuthorizedClientProvider.setSubjectTokenResolver()` with a custom `Function<OAuth2AuthorizationContext, OAuth2Token>`.
  1236. [TIP]
  1237. If you need to resolve an actor token, you can provide `TokenExchangeOAuth2AuthorizedClientProvider.setActorTokenResolver()` with a custom `Function<OAuth2AuthorizationContext, OAuth2Token>`.