authorization-grants.adoc 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167
  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) and
  65. . `client-authentication-method` is set to `none` (`ClientAuthenticationMethod.NONE`)
  66. or
  67. . When `ClientRegistration.clientSettings.requireProofKey` is `true` (in this case `ClientRegistration.authorizationGrantType` must be `authorization_code`)
  68. [TIP]
  69. ====
  70. 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())`.
  71. ====
  72. [[oauth2-client-authorization-code-redirect-uri]]
  73. [[oauth2Client-auth-code-redirect-uri]]The `DefaultOAuth2AuthorizationRequestResolver` also supports `URI` template variables for the `redirect-uri` by using `UriComponentsBuilder`.
  74. The following configuration uses all the supported `URI` template variables:
  75. [source,yaml,attrs="-attributes"]
  76. ----
  77. spring:
  78. security:
  79. oauth2:
  80. client:
  81. registration:
  82. okta:
  83. # ...
  84. redirect-uri: "{baseScheme}://{baseHost}{basePort}{basePath}/authorized/{registrationId}"
  85. # ...
  86. ----
  87. [NOTE]
  88. ====
  89. `+{baseUrl}+` resolves to `+{baseScheme}://{baseHost}{basePort}{basePath}+`
  90. ====
  91. 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].
  92. Doing so ensures that the `X-Forwarded-*` headers are used when expanding the `redirect-uri`.
  93. [[oauth2-client-authorization-code-authorization-request-resolver]]
  94. === Customizing the Authorization Request
  95. 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.
  96. 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].
  97. One of those extended parameters is the `prompt` parameter.
  98. [NOTE]
  99. ====
  100. 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`.
  101. ====
  102. 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`.
  103. [tabs]
  104. ======
  105. Java::
  106. +
  107. [source,java,role="primary"]
  108. ----
  109. @Configuration
  110. @EnableWebSecurity
  111. public class OAuth2LoginSecurityConfig {
  112. @Autowired
  113. private ClientRegistrationRepository clientRegistrationRepository;
  114. @Bean
  115. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  116. http
  117. .authorizeHttpRequests((authorize) -> authorize
  118. .anyRequest().authenticated()
  119. )
  120. .oauth2Login((oauth2) -> oauth2
  121. .authorizationEndpoint((authorization) -> authorization
  122. .authorizationRequestResolver(
  123. authorizationRequestResolver(this.clientRegistrationRepository)
  124. )
  125. )
  126. );
  127. return http.build();
  128. }
  129. private OAuth2AuthorizationRequestResolver authorizationRequestResolver(
  130. ClientRegistrationRepository clientRegistrationRepository) {
  131. DefaultOAuth2AuthorizationRequestResolver authorizationRequestResolver =
  132. new DefaultOAuth2AuthorizationRequestResolver(
  133. clientRegistrationRepository, "/oauth2/authorization");
  134. authorizationRequestResolver.setAuthorizationRequestCustomizer(
  135. authorizationRequestCustomizer());
  136. return authorizationRequestResolver;
  137. }
  138. private Consumer<OAuth2AuthorizationRequest.Builder> authorizationRequestCustomizer() {
  139. return customizer -> customizer
  140. .additionalParameters((params) -> params.put("prompt", "consent"));
  141. }
  142. }
  143. ----
  144. Kotlin::
  145. +
  146. [source,kotlin,role="secondary"]
  147. ----
  148. @Configuration
  149. @EnableWebSecurity
  150. class SecurityConfig {
  151. @Autowired
  152. private lateinit var customClientRegistrationRepository: ClientRegistrationRepository
  153. @Bean
  154. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  155. http {
  156. authorizeHttpRequests {
  157. authorize(anyRequest, authenticated)
  158. }
  159. oauth2Login {
  160. authorizationEndpoint {
  161. authorizationRequestResolver = authorizationRequestResolver(customClientRegistrationRepository)
  162. }
  163. }
  164. }
  165. return http.build()
  166. }
  167. private fun authorizationRequestResolver(
  168. clientRegistrationRepository: ClientRegistrationRepository?): OAuth2AuthorizationRequestResolver {
  169. val authorizationRequestResolver = DefaultOAuth2AuthorizationRequestResolver(
  170. clientRegistrationRepository, "/oauth2/authorization")
  171. authorizationRequestResolver.setAuthorizationRequestCustomizer(
  172. authorizationRequestCustomizer())
  173. return authorizationRequestResolver
  174. }
  175. private fun authorizationRequestCustomizer(): Consumer<OAuth2AuthorizationRequest.Builder> {
  176. return Consumer { customizer ->
  177. customizer
  178. .additionalParameters { params -> params["prompt"] = "consent" }
  179. }
  180. }
  181. }
  182. ----
  183. ======
  184. 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.
  185. For example, if the value for the request parameter `prompt` is always `consent` for the provider `okta`, you can configure it as follows:
  186. [source,yaml]
  187. ----
  188. spring:
  189. security:
  190. oauth2:
  191. client:
  192. provider:
  193. okta:
  194. authorization-uri: https://dev-1234.oktapreview.com/oauth2/v1/authorize?prompt=consent
  195. ----
  196. The preceding example shows the common use case of adding a custom parameter on top of the standard parameters.
  197. Alternatively, if your requirements are more advanced, you can take full control in building the Authorization Request URI by overriding the `OAuth2AuthorizationRequest.authorizationRequestUri` property.
  198. [TIP]
  199. ====
  200. `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.
  201. ====
  202. The following example shows a variation of `authorizationRequestCustomizer()` from the preceding example and instead overrides the `OAuth2AuthorizationRequest.authorizationRequestUri` property:
  203. [tabs]
  204. ======
  205. Java::
  206. +
  207. [source,java,role="primary"]
  208. ----
  209. private Consumer<OAuth2AuthorizationRequest.Builder> authorizationRequestCustomizer() {
  210. return customizer -> customizer
  211. .authorizationRequestUri((uriBuilder) -> uriBuilder
  212. .queryParam("prompt", "consent").build());
  213. }
  214. ----
  215. Kotlin::
  216. +
  217. [source,kotlin,role="secondary"]
  218. ----
  219. private fun authorizationRequestCustomizer(): Consumer<OAuth2AuthorizationRequest.Builder> {
  220. return Consumer { customizer: OAuth2AuthorizationRequest.Builder ->
  221. customizer
  222. .authorizationRequestUri { uriBuilder: UriBuilder ->
  223. uriBuilder
  224. .queryParam("prompt", "consent").build()
  225. }
  226. }
  227. }
  228. ----
  229. ======
  230. [[oauth2-client-authorization-code-authorization-request-repository]]
  231. === Storing the Authorization Request
  232. 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).
  233. [TIP]
  234. ====
  235. The `OAuth2AuthorizationRequest` is used to correlate and validate the Authorization Response.
  236. ====
  237. The default implementation of `AuthorizationRequestRepository` is `HttpSessionOAuth2AuthorizationRequestRepository`, which stores the `OAuth2AuthorizationRequest` in the `HttpSession`.
  238. If you have a custom implementation of `AuthorizationRequestRepository`, you can configure it as follows:
  239. .AuthorizationRequestRepository Configuration
  240. [tabs]
  241. ======
  242. Java::
  243. +
  244. [source,java,role="primary"]
  245. ----
  246. @Configuration
  247. @EnableWebSecurity
  248. public class OAuth2ClientSecurityConfig {
  249. @Bean
  250. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  251. http
  252. .oauth2Client((oauth2) -> oauth2
  253. .authorizationCodeGrant((codeGrant) -> codeGrant
  254. .authorizationRequestRepository(this.authorizationRequestRepository())
  255. // ...
  256. )
  257. )
  258. .oauth2Login((oauth2) -> oauth2
  259. .authorizationEndpoint((endpoint) -> endpoint
  260. .authorizationRequestRepository(this.authorizationRequestRepository())
  261. // ...
  262. )
  263. );
  264. return http.build();
  265. }
  266. @Bean
  267. public AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository() {
  268. return new CustomOAuth2AuthorizationRequestRepository();
  269. }
  270. }
  271. ----
  272. Kotlin::
  273. +
  274. [source,kotlin,role="secondary"]
  275. ----
  276. @Configuration
  277. @EnableWebSecurity
  278. class OAuth2ClientSecurityConfig {
  279. @Bean
  280. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  281. http {
  282. oauth2Client {
  283. authorizationCodeGrant {
  284. authorizationRequestRepository = authorizationRequestRepository()
  285. }
  286. }
  287. }
  288. return http.build()
  289. }
  290. }
  291. ----
  292. Xml::
  293. +
  294. [source,xml,role="secondary"]
  295. ----
  296. <http>
  297. <oauth2-client>
  298. <authorization-code-grant authorization-request-repository-ref="authorizationRequestRepository"/>
  299. </oauth2-client>
  300. </http>
  301. ----
  302. ======
  303. [[oauth2-client-authorization-code-access-token]]
  304. === Requesting an Access Token
  305. [NOTE]
  306. ====
  307. See the https://tools.ietf.org/html/rfc6749#section-4.1.3[Access Token Request/Response] protocol flow for the Authorization Code grant.
  308. ====
  309. The default implementation of `OAuth2AccessTokenResponseClient` for the Authorization Code grant is `RestClientAuthorizationCodeTokenResponseClient`, which uses a `RestClient` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
  310. :section-id: authorization-code
  311. :grant-type: Authorization Code
  312. :class-name: RestClientAuthorizationCodeTokenResponseClient
  313. :grant-request: OAuth2AuthorizationCodeGrantRequest
  314. :leveloffset: +1
  315. include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
  316. :leveloffset: -1
  317. [[oauth2-client-authorization-code-access-token-response-client-dsl]]
  318. === Customize using the DSL
  319. 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:
  320. .Access Token Response Configuration via DSL
  321. [tabs]
  322. ======
  323. Java::
  324. +
  325. [source,java,role="primary"]
  326. ----
  327. @Configuration
  328. @EnableWebSecurity
  329. public class OAuth2ClientSecurityConfig {
  330. @Bean
  331. public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
  332. http
  333. .oauth2Client((oauth2) -> oauth2
  334. .authorizationCodeGrant((codeGrant) -> codeGrant
  335. .accessTokenResponseClient(this.accessTokenResponseClient())
  336. // ...
  337. )
  338. );
  339. return http.build();
  340. }
  341. }
  342. ----
  343. Kotlin::
  344. +
  345. [source,kotlin,role="secondary"]
  346. ----
  347. @Configuration
  348. @EnableWebSecurity
  349. class OAuth2ClientSecurityConfig {
  350. @Bean
  351. open fun filterChain(http: HttpSecurity): SecurityFilterChain {
  352. http {
  353. oauth2Client {
  354. authorizationCodeGrant {
  355. accessTokenResponseClient = accessTokenResponseClient()
  356. }
  357. }
  358. }
  359. return http.build()
  360. }
  361. }
  362. ----
  363. Xml::
  364. +
  365. [source,xml,role="secondary"]
  366. ----
  367. <http>
  368. <oauth2-client>
  369. <authorization-code-grant access-token-response-client-ref="accessTokenResponseClient"/>
  370. </oauth2-client>
  371. </http>
  372. ----
  373. ======
  374. [[oauth2-client-refresh-token]]
  375. == [[oauth2Client-refresh-token-grant]]Refresh Token
  376. [NOTE]
  377. ====
  378. See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.5[Refresh Token].
  379. ====
  380. [[oauth2-client-refresh-token-access-token]]
  381. === Refreshing an Access Token
  382. [NOTE]
  383. ====
  384. See the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant.
  385. ====
  386. The default implementation of `OAuth2AccessTokenResponseClient` for the Refresh Token grant is `RestClientRefreshTokenTokenResponseClient`, which uses a `RestClient` instance to obtain an access token at the Authorization Server’s Token Endpoint.
  387. :section-id: refresh-token
  388. :grant-type: Refresh Token
  389. :class-name: RestClientRefreshTokenTokenResponseClient
  390. :grant-request: OAuth2RefreshTokenGrantRequest
  391. :leveloffset: +1
  392. include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
  393. :leveloffset: -1
  394. [[oauth2-client-refresh-token-authorized-client-provider-builder]]
  395. === Customize using the Builder
  396. 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:
  397. .Access Token Response Configuration via Builder
  398. [tabs]
  399. ======
  400. Java::
  401. +
  402. [source,java,role="primary"]
  403. ----
  404. // Customize
  405. OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenTokenResponseClient = ...
  406. OAuth2AuthorizedClientProvider authorizedClientProvider =
  407. OAuth2AuthorizedClientProviderBuilder.builder()
  408. .authorizationCode()
  409. .refreshToken((configurer) -> configurer.accessTokenResponseClient(refreshTokenTokenResponseClient))
  410. .build();
  411. // ...
  412. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  413. ----
  414. Kotlin::
  415. +
  416. [source,kotlin,role="secondary"]
  417. ----
  418. // Customize
  419. val refreshTokenTokenResponseClient: OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> = ...
  420. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  421. .authorizationCode()
  422. .refreshToken { it.accessTokenResponseClient(refreshTokenTokenResponseClient) }
  423. .build()
  424. // ...
  425. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  426. ----
  427. ======
  428. [NOTE]
  429. ====
  430. `OAuth2AuthorizedClientProviderBuilder.builder().refreshToken()` configures a `RefreshTokenOAuth2AuthorizedClientProvider`,
  431. which is an implementation of an `OAuth2AuthorizedClientProvider` for the Refresh Token grant.
  432. ====
  433. The `OAuth2RefreshToken` can optionally be returned in the Access Token Response for the `authorization_code` grant type.
  434. If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2AuthorizedClient.getAccessToken()` is expired, it is automatically refreshed by the `RefreshTokenOAuth2AuthorizedClientProvider`.
  435. [[oauth2-client-client-credentials]]
  436. == [[oauth2Client-client-creds-grant]]Client Credentials
  437. [NOTE]
  438. ====
  439. 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.
  440. ====
  441. [[oauth2-client-client-credentials-access-token]]
  442. === Requesting an Access Token
  443. [NOTE]
  444. ====
  445. See the https://tools.ietf.org/html/rfc6749#section-4.4.2[Access Token Request/Response] protocol flow for the Client Credentials grant.
  446. ====
  447. The default implementation of `OAuth2AccessTokenResponseClient` for the Client Credentials grant is `RestClientClientCredentialsTokenResponseClient`, which uses a `RestClient` instance to obtain an access token at the Authorization Server’s Token Endpoint.
  448. :section-id: client-credentials
  449. :grant-type: Client Credentials
  450. :class-name: RestClientClientCredentialsTokenResponseClient
  451. :grant-request: OAuth2ClientCredentialsGrantRequest
  452. :leveloffset: +1
  453. include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
  454. :leveloffset: -1
  455. [[oauth2-client-client-credentials-authorized-client-provider-builder]]
  456. === Customize using the Builder
  457. 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:
  458. .Access Token Response Configuration via Builder
  459. [tabs]
  460. ======
  461. Java::
  462. +
  463. [source,java,role="primary"]
  464. ----
  465. // Customize
  466. OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsTokenResponseClient = ...
  467. OAuth2AuthorizedClientProvider authorizedClientProvider =
  468. OAuth2AuthorizedClientProviderBuilder.builder()
  469. .clientCredentials((configurer) -> configurer.accessTokenResponseClient(clientCredentialsTokenResponseClient))
  470. .build();
  471. // ...
  472. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  473. ----
  474. Kotlin::
  475. +
  476. [source,kotlin,role="secondary"]
  477. ----
  478. // Customize
  479. val clientCredentialsTokenResponseClient: OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> = ...
  480. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  481. .clientCredentials { it.accessTokenResponseClient(clientCredentialsTokenResponseClient) }
  482. .build()
  483. // ...
  484. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  485. ----
  486. ======
  487. [NOTE]
  488. ====
  489. `OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials()` configures a `ClientCredentialsOAuth2AuthorizedClientProvider`,
  490. which is an implementation of an `OAuth2AuthorizedClientProvider` for the Client Credentials grant.
  491. ====
  492. [[oauth2-client-client-credentials-authorized-client-manager]]
  493. === Using the Access Token
  494. Consider the following Spring Boot properties for an OAuth 2.0 Client registration:
  495. [source,yaml]
  496. ----
  497. spring:
  498. security:
  499. oauth2:
  500. client:
  501. registration:
  502. okta:
  503. client-id: okta-client-id
  504. client-secret: okta-client-secret
  505. authorization-grant-type: client_credentials
  506. scope: read, write
  507. provider:
  508. okta:
  509. token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
  510. ----
  511. Further consider the following `OAuth2AuthorizedClientManager` `@Bean`:
  512. [tabs]
  513. ======
  514. Java::
  515. +
  516. [source,java,role="primary"]
  517. ----
  518. @Bean
  519. public OAuth2AuthorizedClientManager authorizedClientManager(
  520. ClientRegistrationRepository clientRegistrationRepository,
  521. OAuth2AuthorizedClientRepository authorizedClientRepository) {
  522. OAuth2AuthorizedClientProvider authorizedClientProvider =
  523. OAuth2AuthorizedClientProviderBuilder.builder()
  524. .clientCredentials()
  525. .build();
  526. DefaultOAuth2AuthorizedClientManager authorizedClientManager =
  527. new DefaultOAuth2AuthorizedClientManager(
  528. clientRegistrationRepository, authorizedClientRepository);
  529. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  530. return authorizedClientManager;
  531. }
  532. ----
  533. Kotlin::
  534. +
  535. [source,kotlin,role="secondary"]
  536. ----
  537. @Bean
  538. fun authorizedClientManager(
  539. clientRegistrationRepository: ClientRegistrationRepository,
  540. authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
  541. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  542. .clientCredentials()
  543. .build()
  544. val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
  545. clientRegistrationRepository, authorizedClientRepository)
  546. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  547. return authorizedClientManager
  548. }
  549. ----
  550. ======
  551. Given the preceding properties and bean, you can obtain the `OAuth2AccessToken` as follows:
  552. [tabs]
  553. ======
  554. Java::
  555. +
  556. [source,java,role="primary"]
  557. ----
  558. @Controller
  559. public class OAuth2ClientController {
  560. @Autowired
  561. private OAuth2AuthorizedClientManager authorizedClientManager;
  562. @GetMapping("/")
  563. public String index(Authentication authentication,
  564. HttpServletRequest servletRequest,
  565. HttpServletResponse servletResponse) {
  566. OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  567. .principal(authentication)
  568. .attributes(attrs -> {
  569. attrs.put(HttpServletRequest.class.getName(), servletRequest);
  570. attrs.put(HttpServletResponse.class.getName(), servletResponse);
  571. })
  572. .build();
  573. OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
  574. OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
  575. // ...
  576. return "index";
  577. }
  578. }
  579. ----
  580. Kotlin::
  581. +
  582. [source,kotlin,role="secondary"]
  583. ----
  584. class OAuth2ClientController {
  585. @Autowired
  586. private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
  587. @GetMapping("/")
  588. fun index(authentication: Authentication?,
  589. servletRequest: HttpServletRequest,
  590. servletResponse: HttpServletResponse): String {
  591. val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  592. .principal(authentication)
  593. .attributes(Consumer { attrs: MutableMap<String, Any> ->
  594. attrs[HttpServletRequest::class.java.name] = servletRequest
  595. attrs[HttpServletResponse::class.java.name] = servletResponse
  596. })
  597. .build()
  598. val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
  599. val accessToken: OAuth2AccessToken = authorizedClient.accessToken
  600. // ...
  601. return "index"
  602. }
  603. }
  604. ----
  605. ======
  606. [NOTE]
  607. ====
  608. `HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes.
  609. If not provided, they default to `ServletRequestAttributes` by using `RequestContextHolder.getRequestAttributes()`.
  610. ====
  611. [[oauth2-client-jwt-bearer]]
  612. == JWT Bearer
  613. [NOTE]
  614. ====
  615. 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.
  616. ====
  617. [[oauth2-client-jwt-bearer-access-token]]
  618. === Requesting an Access Token
  619. [NOTE]
  620. ====
  621. 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.
  622. ====
  623. The default implementation of `OAuth2AccessTokenResponseClient` for the JWT Bearer grant is `RestClientJwtBearerTokenResponseClient`, which uses a `RestClient` instance to obtain an access token at the Authorization Server’s Token Endpoint.
  624. :section-id: jwt-bearer
  625. :grant-type: JWT Bearer
  626. :class-name: RestClientJwtBearerTokenResponseClient
  627. :grant-request: JwtBearerGrantRequest
  628. :leveloffset: +1
  629. include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
  630. :leveloffset: -1
  631. [[oauth2-client-jwt-bearer-authorized-client-provider-builder]]
  632. === Customize using the Builder
  633. 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:
  634. .Access Token Response Configuration via Builder
  635. [tabs]
  636. ======
  637. Java::
  638. +
  639. [source,java,role="primary"]
  640. ----
  641. // Customize
  642. OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerTokenResponseClient = ...
  643. JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider = new JwtBearerOAuth2AuthorizedClientProvider();
  644. jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerTokenResponseClient);
  645. OAuth2AuthorizedClientProvider authorizedClientProvider =
  646. OAuth2AuthorizedClientProviderBuilder.builder()
  647. .provider(jwtBearerAuthorizedClientProvider)
  648. .build();
  649. // ...
  650. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  651. ----
  652. Kotlin::
  653. +
  654. [source,kotlin,role="secondary"]
  655. ----
  656. // Customize
  657. val jwtBearerTokenResponseClient: OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> = ...
  658. val jwtBearerAuthorizedClientProvider = JwtBearerOAuth2AuthorizedClientProvider()
  659. jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerTokenResponseClient)
  660. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  661. .provider(jwtBearerAuthorizedClientProvider)
  662. .build()
  663. // ...
  664. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  665. ----
  666. ======
  667. [[oauth2-client-jwt-bearer-authorized-client-manager]]
  668. === Using the Access Token
  669. Given the following Spring Boot properties for an OAuth 2.0 Client registration:
  670. [source,yaml]
  671. ----
  672. spring:
  673. security:
  674. oauth2:
  675. client:
  676. registration:
  677. okta:
  678. client-id: okta-client-id
  679. client-secret: okta-client-secret
  680. authorization-grant-type: urn:ietf:params:oauth:grant-type:jwt-bearer
  681. scope: read
  682. provider:
  683. okta:
  684. token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
  685. ----
  686. ...and the `OAuth2AuthorizedClientManager` `@Bean`:
  687. [tabs]
  688. ======
  689. Java::
  690. +
  691. [source,java,role="primary"]
  692. ----
  693. @Bean
  694. public OAuth2AuthorizedClientManager authorizedClientManager(
  695. ClientRegistrationRepository clientRegistrationRepository,
  696. OAuth2AuthorizedClientRepository authorizedClientRepository) {
  697. JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider =
  698. new JwtBearerOAuth2AuthorizedClientProvider();
  699. OAuth2AuthorizedClientProvider authorizedClientProvider =
  700. OAuth2AuthorizedClientProviderBuilder.builder()
  701. .provider(jwtBearerAuthorizedClientProvider)
  702. .build();
  703. DefaultOAuth2AuthorizedClientManager authorizedClientManager =
  704. new DefaultOAuth2AuthorizedClientManager(
  705. clientRegistrationRepository, authorizedClientRepository);
  706. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  707. return authorizedClientManager;
  708. }
  709. ----
  710. Kotlin::
  711. +
  712. [source,kotlin,role="secondary"]
  713. ----
  714. @Bean
  715. fun authorizedClientManager(
  716. clientRegistrationRepository: ClientRegistrationRepository,
  717. authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
  718. val jwtBearerAuthorizedClientProvider = JwtBearerOAuth2AuthorizedClientProvider()
  719. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  720. .provider(jwtBearerAuthorizedClientProvider)
  721. .build()
  722. val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
  723. clientRegistrationRepository, authorizedClientRepository)
  724. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  725. return authorizedClientManager
  726. }
  727. ----
  728. ======
  729. You may obtain the `OAuth2AccessToken` as follows:
  730. [tabs]
  731. ======
  732. Java::
  733. +
  734. [source,java,role="primary"]
  735. ----
  736. @RestController
  737. public class OAuth2ResourceServerController {
  738. @Autowired
  739. private OAuth2AuthorizedClientManager authorizedClientManager;
  740. @GetMapping("/resource")
  741. public String resource(JwtAuthenticationToken jwtAuthentication) {
  742. OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  743. .principal(jwtAuthentication)
  744. .build();
  745. OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
  746. OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
  747. // ...
  748. }
  749. }
  750. ----
  751. Kotlin::
  752. +
  753. [source,kotlin,role="secondary"]
  754. ----
  755. class OAuth2ResourceServerController {
  756. @Autowired
  757. private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
  758. @GetMapping("/resource")
  759. fun resource(jwtAuthentication: JwtAuthenticationToken?): String {
  760. val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  761. .principal(jwtAuthentication)
  762. .build()
  763. val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
  764. val accessToken: OAuth2AccessToken = authorizedClient.accessToken
  765. // ...
  766. }
  767. }
  768. ----
  769. ======
  770. [NOTE]
  771. ====
  772. `JwtBearerOAuth2AuthorizedClientProvider` resolves the `Jwt` assertion via `OAuth2AuthorizationContext.getPrincipal().getPrincipal()` by default, hence the use of `JwtAuthenticationToken` in the preceding example.
  773. ====
  774. [TIP]
  775. ====
  776. If you need to resolve the `Jwt` assertion from a different source, you can provide `JwtBearerOAuth2AuthorizedClientProvider.setJwtAssertionResolver()` with a custom `Function<OAuth2AuthorizationContext, Jwt>`.
  777. ====
  778. [[oauth2-client-token-exchange]]
  779. == [[oauth2Client-token-exchange-grant]]Token Exchange
  780. [NOTE]
  781. ====
  782. Please refer to OAuth 2.0 Token Exchange for further details on the https://datatracker.ietf.org/doc/html/rfc8693[Token Exchange] grant.
  783. ====
  784. [[oauth2-client-token-exchange-access-token]]
  785. === Requesting an Access Token
  786. [NOTE]
  787. ====
  788. 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.
  789. ====
  790. The default implementation of `OAuth2AccessTokenResponseClient` for the Token Exchange grant is `RestClientTokenExchangeTokenResponseClient`, which uses a `RestClient` instance to obtain an access token at the Authorization Server’s Token Endpoint.
  791. :section-id: token-exchange
  792. :grant-type: Token Exchange
  793. :class-name: RestClientTokenExchangeTokenResponseClient
  794. :grant-request: TokenExchangeGrantRequest
  795. :leveloffset: +1
  796. include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
  797. :leveloffset: -1
  798. [[oauth2-client-token-exchange-authorized-client-provider-builder]]
  799. === Customize using the Builder
  800. 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:
  801. .Access Token Response Configuration via Builder
  802. [tabs]
  803. ======
  804. Java::
  805. +
  806. [source,java,role="primary"]
  807. ----
  808. // Customize
  809. OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeTokenResponseClient = ...
  810. TokenExchangeOAuth2AuthorizedClientProvider tokenExchangeAuthorizedClientProvider = new TokenExchangeOAuth2AuthorizedClientProvider();
  811. tokenExchangeAuthorizedClientProvider.setAccessTokenResponseClient(tokenExchangeTokenResponseClient);
  812. OAuth2AuthorizedClientProvider authorizedClientProvider =
  813. OAuth2AuthorizedClientProviderBuilder.builder()
  814. .provider(tokenExchangeAuthorizedClientProvider)
  815. .build();
  816. // ...
  817. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  818. ----
  819. Kotlin::
  820. +
  821. [source,kotlin,role="secondary"]
  822. ----
  823. // Customize
  824. val tokenExchangeTokenResponseClient: OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> = ...
  825. val tokenExchangeAuthorizedClientProvider = TokenExchangeOAuth2AuthorizedClientProvider()
  826. tokenExchangeAuthorizedClientProvider.setAccessTokenResponseClient(tokenExchangeTokenResponseClient)
  827. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  828. .provider(tokenExchangeAuthorizedClientProvider)
  829. .build()
  830. // ...
  831. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  832. ----
  833. ======
  834. [[oauth2-client-token-exchange-authorized-client-manager]]
  835. === [[token-exchange-grant-access-token]]Using the Access Token
  836. Given the following Spring Boot properties for an OAuth 2.0 Client registration:
  837. [source,yaml]
  838. ----
  839. spring:
  840. security:
  841. oauth2:
  842. client:
  843. registration:
  844. okta:
  845. client-id: okta-client-id
  846. client-secret: okta-client-secret
  847. authorization-grant-type: urn:ietf:params:oauth:grant-type:token-exchange
  848. scope: read
  849. provider:
  850. okta:
  851. token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
  852. ----
  853. ...and the `OAuth2AuthorizedClientManager` `@Bean`:
  854. [tabs]
  855. ======
  856. Java::
  857. +
  858. [source,java,role="primary"]
  859. ----
  860. @Bean
  861. public OAuth2AuthorizedClientManager authorizedClientManager(
  862. ClientRegistrationRepository clientRegistrationRepository,
  863. OAuth2AuthorizedClientRepository authorizedClientRepository) {
  864. TokenExchangeOAuth2AuthorizedClientProvider tokenExchangeAuthorizedClientProvider =
  865. new TokenExchangeOAuth2AuthorizedClientProvider();
  866. OAuth2AuthorizedClientProvider authorizedClientProvider =
  867. OAuth2AuthorizedClientProviderBuilder.builder()
  868. .provider(tokenExchangeAuthorizedClientProvider)
  869. .build();
  870. DefaultOAuth2AuthorizedClientManager authorizedClientManager =
  871. new DefaultOAuth2AuthorizedClientManager(
  872. clientRegistrationRepository, authorizedClientRepository);
  873. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  874. return authorizedClientManager;
  875. }
  876. ----
  877. Kotlin::
  878. +
  879. [source,kotlin,role="secondary"]
  880. ----
  881. @Bean
  882. fun authorizedClientManager(
  883. clientRegistrationRepository: ClientRegistrationRepository,
  884. authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
  885. val tokenExchangeAuthorizedClientProvider = TokenExchangeOAuth2AuthorizedClientProvider()
  886. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  887. .provider(tokenExchangeAuthorizedClientProvider)
  888. .build()
  889. val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
  890. clientRegistrationRepository, authorizedClientRepository)
  891. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  892. return authorizedClientManager
  893. }
  894. ----
  895. ======
  896. You may obtain the `OAuth2AccessToken` as follows:
  897. [tabs]
  898. ======
  899. Java::
  900. +
  901. [source,java,role="primary"]
  902. ----
  903. @RestController
  904. public class OAuth2ResourceServerController {
  905. @Autowired
  906. private OAuth2AuthorizedClientManager authorizedClientManager;
  907. @GetMapping("/resource")
  908. public String resource(JwtAuthenticationToken jwtAuthentication) {
  909. OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  910. .principal(jwtAuthentication)
  911. .build();
  912. OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
  913. OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
  914. // ...
  915. }
  916. }
  917. ----
  918. Kotlin::
  919. +
  920. [source,kotlin,role="secondary"]
  921. ----
  922. class OAuth2ResourceServerController {
  923. @Autowired
  924. private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
  925. @GetMapping("/resource")
  926. fun resource(jwtAuthentication: JwtAuthenticationToken?): String {
  927. val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
  928. .principal(jwtAuthentication)
  929. .build()
  930. val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
  931. val accessToken: OAuth2AccessToken = authorizedClient.accessToken
  932. // ...
  933. }
  934. }
  935. ----
  936. ======
  937. [NOTE]
  938. ====
  939. `TokenExchangeOAuth2AuthorizedClientProvider` resolves the subject token (as an `OAuth2Token`) via `OAuth2AuthorizationContext.getPrincipal().getPrincipal()` by default, hence the use of `JwtAuthenticationToken` in the preceding example.
  940. An actor token is not resolved by default.
  941. ====
  942. [TIP]
  943. ====
  944. If you need to resolve the subject token from a different source, you can provide `TokenExchangeOAuth2AuthorizedClientProvider.setSubjectTokenResolver()` with a custom `Function<OAuth2AuthorizationContext, OAuth2Token>`.
  945. ====
  946. [TIP]
  947. ====
  948. If you need to resolve an actor token, you can provide `TokenExchangeOAuth2AuthorizedClientProvider.setActorTokenResolver()` with a custom `Function<OAuth2AuthorizationContext, OAuth2Token>`.
  949. ====