index.adoc 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067
  1. = OAuth2
  2. Spring Security provides comprehensive OAuth 2.0 support.
  3. This section discusses how to integrate OAuth 2.0 into your servlet based application.
  4. [[oauth2-overview]]
  5. == Overview
  6. Spring Security's OAuth 2.0 support consists of two primary feature sets:
  7. * <<oauth2-resource-server>>
  8. * <<oauth2-client>>
  9. [NOTE]
  10. ====
  11. <<oauth2-client-log-users-in,OAuth2 Login>> is a very powerful OAuth2 Client feature that deserves its own section in the reference documentation.
  12. However, it does not exist as a standalone feature and requires OAuth2 Client in order to function.
  13. ====
  14. These feature sets cover the _resource server_ and _client_ roles defined in the https://tools.ietf.org/html/rfc6749#section-1.1[OAuth 2.0 Authorization Framework], while the _authorization server_ role is covered by https://docs.spring.io/spring-authorization-server/reference/index.html[Spring Authorization Server], which is a separate project built on xref:index.adoc[Spring Security].
  15. The _resource server_ and _client_ roles in OAuth2 are typically represented by one or more server-side applications.
  16. Additionally, the _authorization server_ role can be represented by one or more third parties (as is the case when centralizing identity management and/or authentication within an organization) *-or-* it can be represented by an application (as is the case with Spring Authorization Server).
  17. For example, a typical OAuth2-based microservices architecture might consist of a single user-facing client application, several backend resource servers providing REST APIs and a third party authorization server for managing users and authentication concerns.
  18. It is also common to have a single application representing only one of these roles with the need to integrate with one or more third parties that are providing the other roles.
  19. Spring Security handles these scenarios and more.
  20. The following sections cover the roles provided by Spring Security and contain examples for common scenarios.
  21. [[oauth2-resource-server]]
  22. == OAuth2 Resource Server
  23. [NOTE]
  24. ====
  25. This section contains a summary of OAuth2 Resource Server features with examples.
  26. See xref:servlet/oauth2/resource-server/index.adoc[OAuth 2.0 Resource Server] for complete reference documentation.
  27. ====
  28. To get started, add the `spring-security-oauth2-resource-server` dependency to your project.
  29. When using Spring Boot, add the following starter:
  30. .OAuth2 Client with Spring Boot
  31. [tabs]
  32. ======
  33. Gradle::
  34. +
  35. [source,gradle,role="primary"]
  36. ----
  37. implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
  38. ----
  39. Maven::
  40. +
  41. [source,maven,role="secondary"]
  42. ----
  43. <dependency>
  44. <groupId>org.springframework.boot</groupId>
  45. <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
  46. </dependency>
  47. ----
  48. ======
  49. [TIP]
  50. ====
  51. See xref:getting-spring-security.adoc[] for additional options when not using Spring Boot.
  52. ====
  53. Consider the following use cases for OAuth2 Resource Server:
  54. * I want to <<oauth2-resource-server-access-token,protect access to the API using OAuth2>> (authorization server provides JWT or opaque access token)
  55. * I want to <<oauth2-resource-server-custom-jwt,protect access to the API using a JWT>> (custom token)
  56. [[oauth2-resource-server-access-token]]
  57. === Protect Access with an OAuth2 Access Token
  58. It is very common to protect access to an API using OAuth2 access tokens.
  59. In most cases, Spring Security requires only minimal configuration to secure an application with OAuth2.
  60. There are two types of `Bearer` tokens supported by Spring Security which each use a different component for validation:
  61. * <<oauth2-resource-server-access-token-jwt,JWT support>> uses a `JwtDecoder` bean to validate signatures and decode tokens
  62. * <<oauth2-resource-server-access-token-opaque,Opaque token support>> uses an `OpaqueTokenIntrospector` bean to introspect tokens
  63. [[oauth2-resource-server-access-token-jwt]]
  64. ==== JWT Support
  65. The following example configures a `JwtDecoder` bean using Spring Boot configuration properties:
  66. [source,yaml]
  67. ----
  68. spring:
  69. security:
  70. oauth2:
  71. resourceserver:
  72. jwt:
  73. issuer-uri: https://my-auth-server.com
  74. ----
  75. When using Spring Boot, this is all that is required.
  76. The default arrangement provided by Spring Boot is equivalent to the following:
  77. .Configure Resource Server with JWTs
  78. [tabs]
  79. =====
  80. Java::
  81. +
  82. [source,java,role="primary"]
  83. ----
  84. @Configuration
  85. @EnableWebSecurity
  86. public class SecurityConfig {
  87. @Bean
  88. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  89. http
  90. .authorizeHttpRequests((authorize) -> authorize
  91. .anyRequest().authenticated()
  92. )
  93. .oauth2ResourceServer((oauth2) -> oauth2
  94. .jwt(Customizer.withDefaults())
  95. );
  96. return http.build();
  97. }
  98. @Bean
  99. public JwtDecoder jwtDecoder() {
  100. return JwtDecoders.fromIssuerLocation("https://my-auth-server.com");
  101. }
  102. }
  103. ----
  104. Kotlin::
  105. +
  106. [source,kotlin,role="secondary"]
  107. ----
  108. import org.springframework.security.config.annotation.web.invoke
  109. @Configuration
  110. @EnableWebSecurity
  111. class SecurityConfig {
  112. @Bean
  113. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  114. http {
  115. authorizeHttpRequests {
  116. authorize(anyRequest, authenticated)
  117. }
  118. oauth2ResourceServer {
  119. jwt { }
  120. }
  121. }
  122. return http.build()
  123. }
  124. @Bean
  125. fun jwtDecoder(): JwtDecoder {
  126. return JwtDecoders.fromIssuerLocation("https://my-auth-server.com")
  127. }
  128. }
  129. ----
  130. =====
  131. [[oauth2-resource-server-access-token-opaque]]
  132. ==== Opaque Token Support
  133. The following example configures an `OpaqueTokenIntrospector` bean using Spring Boot configuration properties:
  134. [source,yaml]
  135. ----
  136. spring:
  137. security:
  138. oauth2:
  139. resourceserver:
  140. opaquetoken:
  141. introspection-uri: https://my-auth-server.com/oauth2/introspect
  142. client-id: my-client-id
  143. client-secret: my-client-secret
  144. ----
  145. When using Spring Boot, this is all that is required.
  146. The default arrangement provided by Spring Boot is equivalent to the following:
  147. .Configure Resource Server with Opaque Tokens
  148. [tabs]
  149. =====
  150. Java::
  151. +
  152. [source,java,role="primary"]
  153. ----
  154. @Configuration
  155. @EnableWebSecurity
  156. public class SecurityConfig {
  157. @Bean
  158. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  159. http
  160. .authorizeHttpRequests((authorize) -> authorize
  161. .anyRequest().authenticated()
  162. )
  163. .oauth2ResourceServer((oauth2) -> oauth2
  164. .opaqueToken(Customizer.withDefaults())
  165. );
  166. return http.build();
  167. }
  168. @Bean
  169. public OpaqueTokenIntrospector opaqueTokenIntrospector() {
  170. return new SpringOpaqueTokenIntrospector(
  171. "https://my-auth-server.com/oauth2/introspect", "my-client-id", "my-client-secret");
  172. }
  173. }
  174. ----
  175. Kotlin::
  176. +
  177. [source,kotlin,role="secondary"]
  178. ----
  179. import org.springframework.security.config.annotation.web.invoke
  180. @Configuration
  181. @EnableWebSecurity
  182. class SecurityConfig {
  183. @Bean
  184. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  185. http {
  186. authorizeHttpRequests {
  187. authorize(anyRequest, authenticated)
  188. }
  189. oauth2ResourceServer {
  190. opaqueToken { }
  191. }
  192. }
  193. return http.build()
  194. }
  195. @Bean
  196. fun opaqueTokenIntrospector(): OpaqueTokenIntrospector {
  197. return SpringOpaqueTokenIntrospector(
  198. "https://my-auth-server.com/oauth2/introspect", "my-client-id", "my-client-secret"
  199. )
  200. }
  201. }
  202. ----
  203. =====
  204. [[oauth2-resource-server-custom-jwt]]
  205. === Protect Access with a custom JWT
  206. It is a fairly common goal to protect access to an API using JWTs, particularly when the frontend is developed as a single-page application.
  207. The OAuth2 Resource Server support in Spring Security can be used for any type of `Bearer` token, including a custom JWT.
  208. All that is required to protect an API using JWTs is a `JwtDecoder` bean, which is used to validate signatures and decode tokens.
  209. Spring Security will automatically use the provided bean to configure protection within the `SecurityFilterChain`.
  210. The following example configures a `JwtDecoder` bean using Spring Boot configuration properties:
  211. [source,yaml]
  212. ----
  213. spring:
  214. security:
  215. oauth2:
  216. resourceserver:
  217. jwt:
  218. public-key-location: classpath:my-public-key.pub
  219. ----
  220. [NOTE]
  221. ====
  222. You can provide the public key as a classpath resource (called `my-public-key.pub` in this example).
  223. ====
  224. When using Spring Boot, this is all that is required.
  225. The default arrangement provided by Spring Boot is equivalent to the following:
  226. .Configure Resource Server with Custom JWTs
  227. [tabs]
  228. =====
  229. Java::
  230. +
  231. [source,java,role="primary"]
  232. ----
  233. @Configuration
  234. @EnableWebSecurity
  235. public class SecurityConfig {
  236. @Bean
  237. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  238. http
  239. .authorizeHttpRequests((authorize) -> authorize
  240. .anyRequest().authenticated()
  241. )
  242. .oauth2ResourceServer((oauth2) -> oauth2
  243. .jwt(Customizer.withDefaults())
  244. );
  245. return http.build();
  246. }
  247. @Bean
  248. public JwtDecoder jwtDecoder() {
  249. return NimbusJwtDecoder.withPublicKey(publicKey()).build();
  250. }
  251. private RSAPublicKey publicKey() {
  252. // ...
  253. }
  254. }
  255. ----
  256. Kotlin::
  257. +
  258. [source,kotlin,role="secondary"]
  259. ----
  260. import org.springframework.security.config.annotation.web.invoke
  261. @Configuration
  262. @EnableWebSecurity
  263. class SecurityConfig {
  264. @Bean
  265. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  266. http {
  267. authorizeHttpRequests {
  268. authorize(anyRequest, authenticated)
  269. }
  270. oauth2ResourceServer {
  271. jwt { }
  272. }
  273. }
  274. return http.build()
  275. }
  276. @Bean
  277. fun jwtDecoder(): JwtDecoder {
  278. return NimbusJwtDecoder.withPublicKey(publicKey()).build()
  279. }
  280. private fun publicKey(): RSAPublicKey {
  281. // ...
  282. }
  283. }
  284. ----
  285. =====
  286. [NOTE]
  287. ====
  288. Spring Security does not provide an endpoint for minting tokens.
  289. However, Spring Security does provide the `JwtEncoder` interface along with one implementation, which is `NimbusJwtEncoder`.
  290. ====
  291. [[oauth2-client]]
  292. == OAuth2 Client
  293. [NOTE]
  294. ====
  295. This section contains a summary of OAuth2 Client features with examples.
  296. See xref:servlet/oauth2/client/index.adoc[OAuth 2.0 Client] and xref:servlet/oauth2/login/index.adoc[OAuth 2.0 Login] for complete reference documentation.
  297. ====
  298. To get started, add the `spring-security-oauth2-client` dependency to your project.
  299. When using Spring Boot, add the following starter:
  300. .OAuth2 Client with Spring Boot
  301. [tabs]
  302. ======
  303. Gradle::
  304. +
  305. [source,gradle,role="primary"]
  306. ----
  307. implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
  308. ----
  309. Maven::
  310. +
  311. [source,maven,role="secondary"]
  312. ----
  313. <dependency>
  314. <groupId>org.springframework.boot</groupId>
  315. <artifactId>spring-boot-starter-oauth2-client</artifactId>
  316. </dependency>
  317. ----
  318. ======
  319. [TIP]
  320. ====
  321. See xref:getting-spring-security.adoc[] for additional options when not using Spring Boot.
  322. ====
  323. Consider the following use cases for OAuth2 Client:
  324. * I want to <<oauth2-client-log-users-in,log users in using OAuth 2.0 or OpenID Connect 1.0>>
  325. * I want to <<oauth2-client-access-protected-resources,use `RestClient` to obtain an access token for users>> in order to access a third-party API
  326. * I want to <<oauth2-client-access-protected-resources-webclient,use `WebClient` to obtain an access token for users>> in order to access a third-party API
  327. * I want to <<oauth2-client-access-protected-resources-current-user,do both>> (log users in _and_ access a third-party API)
  328. * I want to <<oauth2-client-client-credentials,use the `client_credentials` grant type>> to obtain a single token per application
  329. * I want to <<oauth2-client-enable-extension-grant-type,enable an extension grant type>>
  330. * I want to <<oauth2-client-customize-existing-grant-type,customize an existing grant type>>
  331. * I want to <<oauth2-client-customize-request-parameters,customize token request parameters>>
  332. * I want to <<oauth2-client-customize-rest-operations,customize the `RestOperations` used by OAuth2 Client components>>
  333. [[oauth2-client-log-users-in]]
  334. === Log Users In with OAuth2
  335. It is very common to require users to log in via OAuth2.
  336. https://openid.net/specs/openid-connect-core-1_0.html[OpenID Connect 1.0] provides a special token called the `id_token` which is designed to provide an OAuth2 Client with the ability to perform user identity verification and log users in.
  337. In certain cases, OAuth2 can be used directly to log users in (as is the case with popular social login providers that do not implement OpenID Connect such as GitHub and Facebook).
  338. The following example configures the application to act as an OAuth2 Client capable of logging users in with OAuth2 or OpenID Connect:
  339. .Configure OAuth2 Login
  340. [tabs]
  341. =====
  342. Java::
  343. +
  344. [source,java,role="primary"]
  345. ----
  346. @Configuration
  347. @EnableWebSecurity
  348. public class SecurityConfig {
  349. @Bean
  350. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  351. http
  352. // ...
  353. .oauth2Login(Customizer.withDefaults());
  354. return http.build();
  355. }
  356. }
  357. ----
  358. Kotlin::
  359. +
  360. [source,kotlin,role="secondary"]
  361. ----
  362. import org.springframework.security.config.annotation.web.invoke
  363. @Configuration
  364. @EnableWebSecurity
  365. class SecurityConfig {
  366. @Bean
  367. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  368. http {
  369. // ...
  370. oauth2Login { }
  371. }
  372. return http.build()
  373. }
  374. }
  375. ----
  376. =====
  377. In addition to the above configuration, the application requires at least one `ClientRegistration` to be configured through the use of a `ClientRegistrationRepository` bean.
  378. The following example configures an `InMemoryClientRegistrationRepository` bean using Spring Boot configuration properties:
  379. [source,yaml]
  380. ----
  381. spring:
  382. security:
  383. oauth2:
  384. client:
  385. registration:
  386. my-oidc-client:
  387. provider: my-oidc-provider
  388. client-id: my-client-id
  389. client-secret: my-client-secret
  390. authorization-grant-type: authorization_code
  391. scope: openid,profile
  392. provider:
  393. my-oidc-provider:
  394. issuer-uri: https://my-oidc-provider.com
  395. ----
  396. With the above configuration, the application now supports two additional endpoints:
  397. 1. The login endpoint (e.g. `/oauth2/authorization/my-oidc-client`) is used to initiate login and perform a redirect to the third party authorization server.
  398. 2. The redirection endpoint (e.g. `/login/oauth2/code/my-oidc-client`) is used by the authorization server to redirect back to the client application, and will contain a `code` parameter used to obtain an `id_token` and/or `access_token` via the access token request.
  399. [NOTE]
  400. ====
  401. The presence of the `openid` scope in the above configuration indicates that OpenID Connect 1.0 should be used.
  402. This instructs Spring Security to use OIDC-specific components (such as `OidcUserService`) during request processing.
  403. Without this scope, Spring Security will use OAuth2-specific components (such as `DefaultOAuth2UserService`) instead.
  404. ====
  405. [[oauth2-client-access-protected-resources]]
  406. === Access Protected Resources
  407. Making requests to a third party API that is protected by OAuth2 is a core use case of OAuth2 Client.
  408. This is accomplished by authorizing a client (represented by the `OAuth2AuthorizedClient` class in Spring Security) and accessing protected resources by placing a `Bearer` token in the `Authorization` header of an outbound request.
  409. The following example configures the application to act as an OAuth2 Client capable of requesting protected resources from a third party API:
  410. .Configure OAuth2 Client
  411. [tabs]
  412. =====
  413. Java::
  414. +
  415. [source,java,role="primary"]
  416. ----
  417. @Configuration
  418. @EnableWebSecurity
  419. public class SecurityConfig {
  420. @Bean
  421. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  422. http
  423. // ...
  424. .oauth2Client(Customizer.withDefaults());
  425. return http.build();
  426. }
  427. }
  428. ----
  429. Kotlin::
  430. +
  431. [source,kotlin,role="secondary"]
  432. ----
  433. import org.springframework.security.config.annotation.web.invoke
  434. @Configuration
  435. @EnableWebSecurity
  436. class SecurityConfig {
  437. @Bean
  438. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  439. http {
  440. // ...
  441. oauth2Client { }
  442. }
  443. return http.build()
  444. }
  445. }
  446. ----
  447. =====
  448. [NOTE]
  449. ====
  450. The above example does not provide a way to log users in.
  451. You can use any other login mechanism (such as `formLogin()`).
  452. See the <<oauth2-client-access-protected-resources-current-user,next section>> for an example combining `oauth2Client()` with `oauth2Login()`.
  453. ====
  454. In addition to the above configuration, the application requires at least one `ClientRegistration` to be configured through the use of a `ClientRegistrationRepository` bean.
  455. The following example configures an `InMemoryClientRegistrationRepository` bean using Spring Boot configuration properties:
  456. [source,yaml]
  457. ----
  458. spring:
  459. security:
  460. oauth2:
  461. client:
  462. registration:
  463. my-oauth2-client:
  464. provider: my-auth-server
  465. client-id: my-client-id
  466. client-secret: my-client-secret
  467. authorization-grant-type: authorization_code
  468. scope: message.read,message.write
  469. provider:
  470. my-auth-server:
  471. issuer-uri: https://my-auth-server.com
  472. ----
  473. In addition to configuring Spring Security to support OAuth2 Client features, you will also need to decide how you will be accessing protected resources and configure your application accordingly.
  474. Spring Security provides implementations of `OAuth2AuthorizedClientManager` for obtaining access tokens that can be used to access protected resources.
  475. [TIP]
  476. ====
  477. Spring Security registers a default `OAuth2AuthorizedClientManager` bean for you when one does not exist.
  478. ====
  479. The easiest way to use an `OAuth2AuthorizedClientManager` is via a `ClientHttpRequestInterceptor` that intercepts requests through a `RestClient`, which is already available when `spring-web` is on the classpath.
  480. The following example uses the default `OAuth2AuthorizedClientManager` to configure a `RestClient` capable of accessing protected resources by placing `Bearer` tokens in the `Authorization` header of each request:
  481. .Configure `RestClient` with `ClientHttpRequestInterceptor`
  482. [tabs]
  483. =====
  484. Java::
  485. +
  486. [source,java,role="primary"]
  487. ----
  488. @Configuration
  489. public class RestClientConfig {
  490. @Bean
  491. public RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) {
  492. OAuth2ClientHttpRequestInterceptor requestInterceptor =
  493. new OAuth2ClientHttpRequestInterceptor(authorizedClientManager);
  494. return RestClient.builder()
  495. .requestInterceptor(requestInterceptor)
  496. .build();
  497. }
  498. }
  499. ----
  500. Kotlin::
  501. +
  502. [source,kotlin,role="secondary"]
  503. ----
  504. @Configuration
  505. class RestClientConfig {
  506. @Bean
  507. fun restClient(authorizedClientManager: OAuth2AuthorizedClientManager): RestClient {
  508. val requestInterceptor = OAuth2ClientHttpRequestInterceptor(authorizedClientManager)
  509. return RestClient.builder()
  510. .requestInterceptor(requestInterceptor)
  511. .build()
  512. }
  513. }
  514. ----
  515. =====
  516. This configured `RestClient` can be used as in the following example:
  517. [[oauth2-client-accessing-protected-resources-example]]
  518. .Use `RestClient` to Access Protected Resources
  519. [tabs]
  520. =====
  521. Java::
  522. +
  523. [source,java,role="primary"]
  524. ----
  525. import static org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId;
  526. @RestController
  527. public class MessagesController {
  528. private final RestClient restClient;
  529. public MessagesController(RestClient restClient) {
  530. this.restClient = restClient;
  531. }
  532. @GetMapping("/messages")
  533. public ResponseEntity<List<Message>> messages() {
  534. Message[] messages = this.restClient.get()
  535. .uri("http://localhost:8090/messages")
  536. .attributes(clientRegistrationId("my-oauth2-client"))
  537. .retrieve()
  538. .body(Message[].class);
  539. return ResponseEntity.ok(Arrays.asList(messages));
  540. }
  541. public record Message(String message) {
  542. }
  543. }
  544. ----
  545. Kotlin::
  546. +
  547. [source,kotlin,role="secondary"]
  548. ----
  549. import org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId
  550. import org.springframework.web.client.body
  551. @RestController
  552. class MessagesController(private val restClient: RestClient) {
  553. @GetMapping("/messages")
  554. fun messages(): ResponseEntity<List<Message>> {
  555. val messages = restClient.get()
  556. .uri("http://localhost:8090/messages")
  557. .attributes(clientRegistrationId("my-oauth2-client"))
  558. .retrieve()
  559. .body<Array<Message>>()!!
  560. .toList()
  561. return ResponseEntity.ok(messages)
  562. }
  563. data class Message(val message: String)
  564. }
  565. ----
  566. =====
  567. [[oauth2-client-access-protected-resources-webclient]]
  568. === Access Protected Resources with `WebClient`
  569. Making requests to a third party API that is protected by OAuth2 is a core use case of OAuth2 Client.
  570. This is accomplished by authorizing a client (represented by the `OAuth2AuthorizedClient` class in Spring Security) and accessing protected resources by placing a `Bearer` token in the `Authorization` header of an outbound request.
  571. The following example configures the application to act as an OAuth2 Client capable of requesting protected resources from a third party API:
  572. .Configure OAuth2 Client
  573. [tabs]
  574. =====
  575. Java::
  576. +
  577. [source,java,role="primary"]
  578. ----
  579. @Configuration
  580. @EnableWebSecurity
  581. public class SecurityConfig {
  582. @Bean
  583. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  584. http
  585. // ...
  586. .oauth2Client(Customizer.withDefaults());
  587. return http.build();
  588. }
  589. }
  590. ----
  591. Kotlin::
  592. +
  593. [source,kotlin,role="secondary"]
  594. ----
  595. import org.springframework.security.config.annotation.web.invoke
  596. @Configuration
  597. @EnableWebSecurity
  598. class SecurityConfig {
  599. @Bean
  600. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  601. http {
  602. // ...
  603. oauth2Client { }
  604. }
  605. return http.build()
  606. }
  607. }
  608. ----
  609. =====
  610. [NOTE]
  611. ====
  612. The above example does not provide a way to log users in.
  613. You can use any other login mechanism (such as `formLogin()`).
  614. See the <<oauth2-client-access-protected-resources-current-user,previous section>> for an example combining `oauth2Client()` with `oauth2Login()`.
  615. ====
  616. In addition to the above configuration, the application requires at least one `ClientRegistration` to be configured through the use of a `ClientRegistrationRepository` bean.
  617. The following example configures an `InMemoryClientRegistrationRepository` bean using Spring Boot configuration properties:
  618. [source,yaml]
  619. ----
  620. spring:
  621. security:
  622. oauth2:
  623. client:
  624. registration:
  625. my-oauth2-client:
  626. provider: my-auth-server
  627. client-id: my-client-id
  628. client-secret: my-client-secret
  629. authorization-grant-type: authorization_code
  630. scope: message.read,message.write
  631. provider:
  632. my-auth-server:
  633. issuer-uri: https://my-auth-server.com
  634. ----
  635. In addition to configuring Spring Security to support OAuth2 Client features, you will also need to decide how you will be accessing protected resources and configure your application accordingly.
  636. Spring Security provides implementations of `OAuth2AuthorizedClientManager` for obtaining access tokens that can be used to access protected resources.
  637. [TIP]
  638. ====
  639. Spring Security registers a default `OAuth2AuthorizedClientManager` bean for you when one does not exist.
  640. ====
  641. <<oauth2-client-access-protected-resources,Instead of configuring a `RestClient`>>, another way to use an `OAuth2AuthorizedClientManager` is via an `ExchangeFilterFunction` that intercepts requests through a `WebClient`.
  642. To use `WebClient`, you will need to add the `spring-webflux` dependency along with a reactive client implementation:
  643. .Add Spring WebFlux Dependency
  644. [tabs]
  645. ======
  646. Gradle::
  647. +
  648. [source,gradle,role="primary"]
  649. ----
  650. implementation 'org.springframework:spring-webflux'
  651. implementation 'io.projectreactor.netty:reactor-netty'
  652. ----
  653. Maven::
  654. +
  655. [source,maven,role="secondary"]
  656. ----
  657. <dependency>
  658. <groupId>org.springframework</groupId>
  659. <artifactId>spring-webflux</artifactId>
  660. </dependency>
  661. <dependency>
  662. <groupId>io.projectreactor.netty</groupId>
  663. <artifactId>reactor-netty</artifactId>
  664. </dependency>
  665. ----
  666. ======
  667. The following example uses the default `OAuth2AuthorizedClientManager` to configure a `WebClient` capable of accessing protected resources by placing `Bearer` tokens in the `Authorization` header of each request:
  668. .Configure `WebClient` with `ExchangeFilterFunction`
  669. [tabs]
  670. =====
  671. Java::
  672. +
  673. [source,java,role="primary"]
  674. ----
  675. @Configuration
  676. public class WebClientConfig {
  677. @Bean
  678. public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
  679. ServletOAuth2AuthorizedClientExchangeFilterFunction filter =
  680. new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
  681. return WebClient.builder()
  682. .apply(filter.oauth2Configuration())
  683. .build();
  684. }
  685. }
  686. ----
  687. Kotlin::
  688. +
  689. [source,kotlin,role="secondary"]
  690. ----
  691. @Configuration
  692. class WebClientConfig {
  693. @Bean
  694. fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager): WebClient {
  695. val filter = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
  696. return WebClient.builder()
  697. .apply(filter.oauth2Configuration())
  698. .build()
  699. }
  700. }
  701. ----
  702. =====
  703. This configured `WebClient` can be used as in the following example:
  704. .Use `WebClient` to Access Protected Resources
  705. [tabs]
  706. =====
  707. Java::
  708. +
  709. [source,java,role="primary"]
  710. ----
  711. import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
  712. @RestController
  713. public class MessagesController {
  714. private final WebClient webClient;
  715. public MessagesController(WebClient webClient) {
  716. this.webClient = webClient;
  717. }
  718. @GetMapping("/messages")
  719. public ResponseEntity<List<Message>> messages() {
  720. return this.webClient.get()
  721. .uri("http://localhost:8090/messages")
  722. .attributes(clientRegistrationId("my-oauth2-client"))
  723. .retrieve()
  724. .toEntityList(Message.class)
  725. .block();
  726. }
  727. public record Message(String message) {
  728. }
  729. }
  730. ----
  731. Kotlin::
  732. +
  733. [source,kotlin,role="secondary"]
  734. ----
  735. import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId
  736. @RestController
  737. class MessagesController(private val webClient: WebClient) {
  738. @GetMapping("/messages")
  739. fun messages(): ResponseEntity<List<Message>> {
  740. return webClient.get()
  741. .uri("http://localhost:8090/messages")
  742. .attributes(clientRegistrationId("my-oauth2-client"))
  743. .retrieve()
  744. .toEntityList<Message>()
  745. .block()!!
  746. }
  747. data class Message(val message: String)
  748. }
  749. ----
  750. =====
  751. [[oauth2-client-access-protected-resources-current-user]]
  752. === Access Protected Resources for the Current User
  753. When a user is logged in via OAuth2 or OpenID Connect, the authorization server may provide an access token that can be used directly to access protected resources.
  754. This is convenient because it only requires a single `ClientRegistration` to be configured for both use cases simultaneously.
  755. [NOTE]
  756. ====
  757. This section combines <<oauth2-client-log-users-in>> and <<oauth2-client-access-protected-resources>> into a single configuration.
  758. Other advanced scenarios exist, such as configuring one `ClientRegistration` for login and another for accessing protected resources.
  759. All such scenarios would use the same basic configuration.
  760. ====
  761. The following example configures the application to act as an OAuth2 Client capable of logging the user in _and_ requesting protected resources from a third party API:
  762. .Configure OAuth2 Login and OAuth2 Client
  763. [tabs]
  764. =====
  765. Java::
  766. +
  767. [source,java,role="primary"]
  768. ----
  769. @Configuration
  770. @EnableWebSecurity
  771. public class SecurityConfig {
  772. @Bean
  773. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  774. http
  775. // ...
  776. .oauth2Login(Customizer.withDefaults())
  777. .oauth2Client(Customizer.withDefaults());
  778. return http.build();
  779. }
  780. }
  781. ----
  782. Kotlin::
  783. +
  784. [source,kotlin,role="secondary"]
  785. ----
  786. import org.springframework.security.config.annotation.web.invoke
  787. @Configuration
  788. @EnableWebSecurity
  789. class SecurityConfig {
  790. @Bean
  791. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  792. http {
  793. // ...
  794. oauth2Login { }
  795. oauth2Client { }
  796. }
  797. return http.build()
  798. }
  799. }
  800. ----
  801. =====
  802. In addition to the above configuration, the application requires at least one `ClientRegistration` to be configured through the use of a `ClientRegistrationRepository` bean.
  803. The following example configures an `InMemoryClientRegistrationRepository` bean using Spring Boot configuration properties:
  804. [source,yaml]
  805. ----
  806. spring:
  807. security:
  808. oauth2:
  809. client:
  810. registration:
  811. my-combined-client:
  812. provider: my-auth-server
  813. client-id: my-client-id
  814. client-secret: my-client-secret
  815. authorization-grant-type: authorization_code
  816. scope: openid,profile,message.read,message.write
  817. provider:
  818. my-auth-server:
  819. issuer-uri: https://my-auth-server.com
  820. ----
  821. [NOTE]
  822. ====
  823. The main difference between the previous examples (<<oauth2-client-log-users-in>>, <<oauth2-client-access-protected-resources>>) and this one is what is configured via the `scope` property, which combines the standard scopes `openid` and `profile` with the custom scopes `message.read` and `message.write`.
  824. ====
  825. In addition to configuring Spring Security to support OAuth2 Client features, you will also need to decide how you will be accessing protected resources and configure your application accordingly.
  826. Spring Security provides implementations of `OAuth2AuthorizedClientManager` for obtaining access tokens that can be used to access protected resources.
  827. [TIP]
  828. ====
  829. Spring Security registers a default `OAuth2AuthorizedClientManager` bean for you when one does not exist.
  830. ====
  831. The easiest way to use an `OAuth2AuthorizedClientManager` is via a `ClientHttpRequestInterceptor` that intercepts requests through a `RestClient`, which is already available when `spring-web` is on the classpath.
  832. The following example uses the default `OAuth2AuthorizedClientManager` to configure a `RestClient` capable of accessing protected resources by placing `Bearer` tokens in the `Authorization` header of each request:
  833. .Configure `RestClient` with `ClientHttpRequestInterceptor`
  834. [tabs]
  835. =====
  836. Java::
  837. +
  838. [source,java,role="primary"]
  839. ----
  840. @Configuration
  841. public class RestClientConfig {
  842. @Bean
  843. public RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) {
  844. OAuth2ClientHttpRequestInterceptor requestInterceptor =
  845. new OAuth2ClientHttpRequestInterceptor(authorizedClientManager, clientRegistrationIdResolver());
  846. return RestClient.builder()
  847. .requestInterceptor(requestInterceptor)
  848. .build();
  849. }
  850. private static ClientRegistrationIdResolver clientRegistrationIdResolver() {
  851. return (request) -> {
  852. Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
  853. return (authentication instanceof OAuth2AuthenticationToken principal)
  854. ? principal.getAuthorizedClientRegistrationId()
  855. : null;
  856. };
  857. }
  858. }
  859. ----
  860. Kotlin::
  861. +
  862. [source,kotlin,role="secondary"]
  863. ----
  864. @Configuration
  865. class RestClientConfig {
  866. @Bean
  867. fun restClient(authorizedClientManager: OAuth2AuthorizedClientManager): RestClient {
  868. val requestInterceptor = OAuth2ClientHttpRequestInterceptor(authorizedClientManager, clientRegistrationIdResolver())
  869. return RestClient.builder()
  870. .requestInterceptor(requestInterceptor)
  871. .build()
  872. }
  873. private fun clientRegistrationIdResolver(): OAuth2ClientHttpRequestInterceptor.ClientRegistrationIdResolver {
  874. return OAuth2ClientHttpRequestInterceptor.ClientRegistrationIdResolver { request ->
  875. val authentication = SecurityContextHolder.getContext().authentication
  876. if (authentication is OAuth2AuthenticationToken) {
  877. authentication.authorizedClientRegistrationId
  878. } else {
  879. null
  880. }
  881. }
  882. }
  883. }
  884. ----
  885. =====
  886. This configured `RestClient` can be used as in the following example:
  887. [[oauth2-client-accessing-protected-resources-current-user-example]]
  888. .Use `RestClient` to Access Protected Resources (Current User)
  889. [tabs]
  890. =====
  891. Java::
  892. +
  893. [source,java,role="primary"]
  894. ----
  895. @RestController
  896. public class MessagesController {
  897. private final RestClient restClient;
  898. public MessagesController(RestClient restClient) {
  899. this.restClient = restClient;
  900. }
  901. @GetMapping("/messages")
  902. public ResponseEntity<List<Message>> messages() {
  903. Message[] messages = this.restClient.get()
  904. .uri("http://localhost:8090/messages")
  905. .retrieve()
  906. .body(Message[].class);
  907. return ResponseEntity.ok(Arrays.asList(messages));
  908. }
  909. public record Message(String message) {
  910. }
  911. }
  912. ----
  913. Kotlin::
  914. +
  915. [source,kotlin,role="secondary"]
  916. ----
  917. import org.springframework.web.client.body
  918. @RestController
  919. class MessagesController(private val restClient: RestClient) {
  920. @GetMapping("/messages")
  921. fun messages(): ResponseEntity<List<Message>> {
  922. val messages = restClient.get()
  923. .uri("http://localhost:8090/messages")
  924. .retrieve()
  925. .body<Array<Message>>()!!
  926. .toList()
  927. return ResponseEntity.ok(messages)
  928. }
  929. data class Message(val message: String)
  930. }
  931. ----
  932. =====
  933. [NOTE]
  934. ====
  935. Unlike the <<oauth2-client-accessing-protected-resources-example,previous example>>, notice that we do not need to tell Spring Security about the `clientRegistrationId` we'd like to use.
  936. This is because it can be derived from the currently logged in user.
  937. ====
  938. [[oauth2-client-client-credentials]]
  939. === Use the Client Credentials Grant
  940. [NOTE]
  941. ====
  942. This section focuses on additional considerations for the client credentials grant type.
  943. See <<oauth2-client-access-protected-resources>> for general setup and usage with all grant types.
  944. ====
  945. The https://tools.ietf.org/html/rfc6749#section-1.3.4[client credentials grant] allows a client to obtain an `access_token` on behalf of itself.
  946. The client credentials grant is a simple flow that does not involve a resource owner (i.e. a user).
  947. [WARNING]
  948. ====
  949. It is important to note that typical use of the client credentials grant implies that any request (or user) can potentially obtain an access token and make protected resources requests to a resource server.
  950. Exercise caution when designing applications to ensure that users cannot make unauthorized requests since every request will be able to obtain an access token.
  951. ====
  952. When obtaining access tokens within a web application where users can log in, the default behavior of Spring Security is to obtain an access token per user.
  953. [NOTE]
  954. ====
  955. By default, access tokens are scoped to the principal name of the current user which means every user will receive a unique access token.
  956. ====
  957. Clients using the client credentials grant typically require access tokens to be scoped to the application instead of to individual users so there is only one access token per application.
  958. In order to scope access tokens to the application, you will need to set a strategy for resolving a custom principal name.
  959. The following example does this by configuring a `RestClient` with the `RequestAttributePrincipalResolver`:
  960. .Configure `RestClient` for `client_credentials`
  961. [tabs]
  962. =====
  963. Java::
  964. +
  965. [source,java,role="primary"]
  966. ----
  967. @Configuration
  968. public class RestClientConfig {
  969. @Bean
  970. public RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) {
  971. OAuth2ClientHttpRequestInterceptor requestInterceptor =
  972. new OAuth2ClientHttpRequestInterceptor(authorizedClientManager);
  973. requestInterceptor.setPrincipalResolver(new RequestAttributePrincipalResolver());
  974. return RestClient.builder()
  975. .requestInterceptor(requestInterceptor)
  976. .build();
  977. }
  978. }
  979. ----
  980. Kotlin::
  981. +
  982. [source,kotlin,role="secondary"]
  983. ----
  984. @Configuration
  985. class RestClientConfig {
  986. @Bean
  987. fun restClient(authorizedClientManager: OAuth2AuthorizedClientManager): RestClient {
  988. val requestInterceptor = OAuth2ClientHttpRequestInterceptor(authorizedClientManager)
  989. requestInterceptor.setPrincipalResolver(RequestAttributePrincipalResolver())
  990. return RestClient.builder()
  991. .requestInterceptor(requestInterceptor)
  992. .build()
  993. }
  994. }
  995. ----
  996. =====
  997. With the above configuration in place, a principal name can be specified for each request.
  998. The following example demonstrates how to scope access tokens to the application by specifying a principal name:
  999. .Scope Access Tokens to the Application
  1000. [tabs]
  1001. =====
  1002. Java::
  1003. +
  1004. [source,java,role="primary"]
  1005. ----
  1006. import static org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId;
  1007. import static org.springframework.security.oauth2.client.web.client.RequestAttributePrincipalResolver.principal;
  1008. @RestController
  1009. public class MessagesController {
  1010. private final RestClient restClient;
  1011. public MessagesController(RestClient restClient) {
  1012. this.restClient = restClient;
  1013. }
  1014. @GetMapping("/messages")
  1015. public ResponseEntity<List<Message>> messages() {
  1016. Message[] messages = this.restClient.get()
  1017. .uri("http://localhost:8090/messages")
  1018. .attributes(clientRegistrationId("my-oauth2-client"))
  1019. .attributes(principal("my-application"))
  1020. .retrieve()
  1021. .body(Message[].class);
  1022. return ResponseEntity.ok(Arrays.asList(messages));
  1023. }
  1024. public record Message(String message) {
  1025. }
  1026. }
  1027. ----
  1028. Kotlin::
  1029. +
  1030. [source,kotlin,role="secondary"]
  1031. ----
  1032. import org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId
  1033. import org.springframework.security.oauth2.client.web.client.RequestAttributePrincipalResolver.principal
  1034. import org.springframework.web.client.body
  1035. @RestController
  1036. class MessagesController(private val restClient: RestClient) {
  1037. @GetMapping("/messages")
  1038. fun messages(): ResponseEntity<List<Message>> {
  1039. val messages = restClient.get()
  1040. .uri("http://localhost:8090/messages")
  1041. .attributes(clientRegistrationId("my-oauth2-client"))
  1042. .attributes(principal("my-application"))
  1043. .retrieve()
  1044. .body<Array<Message>>()!!
  1045. .toList()
  1046. return ResponseEntity.ok(messages)
  1047. }
  1048. data class Message(val message: String)
  1049. }
  1050. ----
  1051. =====
  1052. [NOTE]
  1053. ====
  1054. When specifying a principal name via attributes as in the above example, there will only be a single access token and it will be used for all requests.
  1055. ====
  1056. [[oauth2-client-enable-extension-grant-type]]
  1057. === Enable an Extension Grant Type
  1058. A common use case involves enabling and/or configuring an extension grant type.
  1059. For example, Spring Security provides support for the `jwt-bearer` and `token-exchange` grant types, but does not enable them by default because they are not part of the core OAuth 2.0 specification.
  1060. With Spring Security 6.2 and later, we can simply publish a bean for one or more `OAuth2AuthorizedClientProvider` and they will be picked up automatically.
  1061. The following example simply enables the `jwt-bearer` grant type:
  1062. .Enable `jwt-bearer` Grant Type
  1063. [tabs]
  1064. =====
  1065. Java::
  1066. +
  1067. [source,java,role="primary"]
  1068. ----
  1069. @Configuration
  1070. public class SecurityConfig {
  1071. @Bean
  1072. public OAuth2AuthorizedClientProvider jwtBearer() {
  1073. return new JwtBearerOAuth2AuthorizedClientProvider();
  1074. }
  1075. }
  1076. ----
  1077. Kotlin::
  1078. +
  1079. [source,kotlin,role="secondary"]
  1080. ----
  1081. @Configuration
  1082. class SecurityConfig {
  1083. @Bean
  1084. fun jwtBearer(): OAuth2AuthorizedClientProvider {
  1085. return JwtBearerOAuth2AuthorizedClientProvider()
  1086. }
  1087. }
  1088. ----
  1089. =====
  1090. A default `OAuth2AuthorizedClientManager` will be published automatically by Spring Security when one is not already provided.
  1091. [TIP]
  1092. ====
  1093. Any custom `OAuth2AuthorizedClientProvider` bean will also be picked up and applied to the provided `OAuth2AuthorizedClientManager` after the default grant types.
  1094. ====
  1095. In order to achieve the above configuration prior to Spring Security 6.2, we had to publish this bean ourselves and ensure we re-enabled default grant types as well.
  1096. To understand what is being configured behind the scenes, here's what the configuration might have looked like:
  1097. .Enable `jwt-bearer` Grant Type (prior to 6.2)
  1098. [tabs]
  1099. =====
  1100. Java::
  1101. +
  1102. [source,java,role="primary"]
  1103. ----
  1104. @Configuration
  1105. public class SecurityConfig {
  1106. @Bean
  1107. public OAuth2AuthorizedClientManager authorizedClientManager(
  1108. ClientRegistrationRepository clientRegistrationRepository,
  1109. OAuth2AuthorizedClientRepository authorizedClientRepository) {
  1110. OAuth2AuthorizedClientProvider authorizedClientProvider =
  1111. OAuth2AuthorizedClientProviderBuilder.builder()
  1112. .authorizationCode()
  1113. .refreshToken()
  1114. .clientCredentials()
  1115. .password()
  1116. .provider(new JwtBearerOAuth2AuthorizedClientProvider())
  1117. .build();
  1118. DefaultOAuth2AuthorizedClientManager authorizedClientManager =
  1119. new DefaultOAuth2AuthorizedClientManager(
  1120. clientRegistrationRepository, authorizedClientRepository);
  1121. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  1122. return authorizedClientManager;
  1123. }
  1124. }
  1125. ----
  1126. Kotlin::
  1127. +
  1128. [source,kotlin,role="secondary"]
  1129. ----
  1130. @Configuration
  1131. class SecurityConfig {
  1132. @Bean
  1133. fun authorizedClientManager(
  1134. clientRegistrationRepository: ClientRegistrationRepository,
  1135. authorizedClientRepository: OAuth2AuthorizedClientRepository
  1136. ): OAuth2AuthorizedClientManager {
  1137. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  1138. .authorizationCode()
  1139. .refreshToken()
  1140. .clientCredentials()
  1141. .password()
  1142. .provider(JwtBearerOAuth2AuthorizedClientProvider())
  1143. .build()
  1144. val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
  1145. clientRegistrationRepository, authorizedClientRepository
  1146. )
  1147. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  1148. return authorizedClientManager
  1149. }
  1150. }
  1151. ----
  1152. =====
  1153. [[oauth2-client-customize-existing-grant-type]]
  1154. === Customize an Existing Grant Type
  1155. The ability to <<oauth2-client-enable-extension-grant-type,enable extension grant types>> by publishing a bean also provides the opportunity for customizing an existing grant type without the need to re-define the defaults.
  1156. For example, if we want to customize the clock skew of the `OAuth2AuthorizedClientProvider` for the `client_credentials` grant, we can simply publish a bean like so:
  1157. .Customize Client Credentials Grant Type
  1158. [tabs]
  1159. =====
  1160. Java::
  1161. +
  1162. [source,java,role="primary"]
  1163. ----
  1164. @Configuration
  1165. public class SecurityConfig {
  1166. @Bean
  1167. public OAuth2AuthorizedClientProvider clientCredentials() {
  1168. ClientCredentialsOAuth2AuthorizedClientProvider authorizedClientProvider =
  1169. new ClientCredentialsOAuth2AuthorizedClientProvider();
  1170. authorizedClientProvider.setClockSkew(Duration.ofMinutes(5));
  1171. return authorizedClientProvider;
  1172. }
  1173. }
  1174. ----
  1175. Kotlin::
  1176. +
  1177. [source,kotlin,role="secondary"]
  1178. ----
  1179. @Configuration
  1180. class SecurityConfig {
  1181. @Bean
  1182. fun clientCredentials(): OAuth2AuthorizedClientProvider {
  1183. val authorizedClientProvider = ClientCredentialsOAuth2AuthorizedClientProvider()
  1184. authorizedClientProvider.setClockSkew(Duration.ofMinutes(5))
  1185. return authorizedClientProvider
  1186. }
  1187. }
  1188. ----
  1189. =====
  1190. [[oauth2-client-customize-request-parameters]]
  1191. === Customize Token Request Parameters
  1192. The need to customize request parameters when obtaining an access token is fairly common.
  1193. For example, let's say we want to add a custom `audience` parameter to the token request because the provider requires this parameter for the `authorization_code` grant.
  1194. With Spring Security 6.2 and later, we can simply publish a bean of type `OAuth2AccessTokenResponseClient` with the generic type `OAuth2AuthorizationCodeGrantRequest` and it will be used by Spring Security to configure OAuth2 Client components.
  1195. The following example customizes token request parameters for the `authorization_code` grant without the DSL:
  1196. .Customize Token Request Parameters for Authorization Code Grant
  1197. [tabs]
  1198. =====
  1199. Java::
  1200. +
  1201. [source,java,role="primary"]
  1202. ----
  1203. @Configuration
  1204. public class SecurityConfig {
  1205. @Bean
  1206. public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() {
  1207. OAuth2AuthorizationCodeGrantRequestEntityConverter requestEntityConverter =
  1208. new OAuth2AuthorizationCodeGrantRequestEntityConverter();
  1209. requestEntityConverter.addParametersConverter(parametersConverter());
  1210. DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
  1211. new DefaultAuthorizationCodeTokenResponseClient();
  1212. accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
  1213. return accessTokenResponseClient;
  1214. }
  1215. private static Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> parametersConverter() {
  1216. return (grantRequest) -> {
  1217. MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
  1218. parameters.set("audience", "xyz_value");
  1219. return parameters;
  1220. };
  1221. }
  1222. }
  1223. ----
  1224. Kotlin::
  1225. +
  1226. [source,kotlin,role="secondary"]
  1227. ----
  1228. @Configuration
  1229. class SecurityConfig {
  1230. @Bean
  1231. fun authorizationCodeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {
  1232. val requestEntityConverter = OAuth2AuthorizationCodeGrantRequestEntityConverter()
  1233. requestEntityConverter.addParametersConverter(parametersConverter())
  1234. val accessTokenResponseClient = DefaultAuthorizationCodeTokenResponseClient()
  1235. accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter)
  1236. return accessTokenResponseClient
  1237. }
  1238. private fun parametersConverter(): Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> {
  1239. return Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> { grantRequest ->
  1240. LinkedMultiValueMap<String, String>().also { parameters ->
  1241. parameters["audience"] = "xyz_value"
  1242. }
  1243. }
  1244. }
  1245. }
  1246. ----
  1247. =====
  1248. [TIP]
  1249. ====
  1250. Notice that we don't need to customize the `SecurityFilterChain` bean in this case, and can stick with the defaults.
  1251. If using Spring Boot with no additional customizations, we can actually omit the `SecurityFilterChain` bean entirely.
  1252. ====
  1253. Prior to Spring Security 6.2, we had to ensure that this customization was applied for both OAuth2 Login (if we are using this feature) and OAuth2 Client components using the Spring Security DSL.
  1254. To understand what is being configured behind the scenes, here's what the configuration might have looked like:
  1255. .Customize Token Request Parameters for Authorization Code Grant (prior to 6.2)
  1256. [tabs]
  1257. =====
  1258. Java::
  1259. +
  1260. [source,java,role="primary"]
  1261. ----
  1262. @Configuration
  1263. @EnableWebSecurity
  1264. public class SecurityConfig {
  1265. @Bean
  1266. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  1267. OAuth2AuthorizationCodeGrantRequestEntityConverter requestEntityConverter =
  1268. new OAuth2AuthorizationCodeGrantRequestEntityConverter();
  1269. requestEntityConverter.addParametersConverter(parametersConverter());
  1270. DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
  1271. new DefaultAuthorizationCodeTokenResponseClient();
  1272. accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
  1273. http
  1274. .authorizeHttpRequests((authorize) -> authorize
  1275. .anyRequest().authenticated()
  1276. )
  1277. .oauth2Login((oauth2Login) -> oauth2Login
  1278. .tokenEndpoint((tokenEndpoint) -> tokenEndpoint
  1279. .accessTokenResponseClient(accessTokenResponseClient)
  1280. )
  1281. )
  1282. .oauth2Client((oauth2Client) -> oauth2Client
  1283. .authorizationCodeGrant((authorizationCode) -> authorizationCode
  1284. .accessTokenResponseClient(accessTokenResponseClient)
  1285. )
  1286. );
  1287. return http.build();
  1288. }
  1289. private static Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> parametersConverter() {
  1290. // ...
  1291. }
  1292. }
  1293. ----
  1294. Kotlin::
  1295. +
  1296. [source,kotlin,role="secondary"]
  1297. ----
  1298. import org.springframework.security.config.annotation.web.invoke
  1299. @Configuration
  1300. @EnableWebSecurity
  1301. class SecurityConfig {
  1302. @Bean
  1303. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  1304. val requestEntityConverter = OAuth2AuthorizationCodeGrantRequestEntityConverter()
  1305. requestEntityConverter.addParametersConverter(parametersConverter())
  1306. val tokenResponseClient = DefaultAuthorizationCodeTokenResponseClient()
  1307. tokenResponseClient.setRequestEntityConverter(requestEntityConverter)
  1308. http {
  1309. authorizeHttpRequests {
  1310. authorize(anyRequest, authenticated)
  1311. }
  1312. oauth2Login {
  1313. tokenEndpoint {
  1314. accessTokenResponseClient = tokenResponseClient
  1315. }
  1316. }
  1317. oauth2Client {
  1318. authorizationCodeGrant {
  1319. accessTokenResponseClient = tokenResponseClient
  1320. }
  1321. }
  1322. }
  1323. return http.build()
  1324. }
  1325. private fun parametersConverter(): Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> {
  1326. // ...
  1327. }
  1328. }
  1329. ----
  1330. =====
  1331. For other grant types we can publish additional `OAuth2AccessTokenResponseClient` beans to override the defaults.
  1332. For example, to customize token requests for the `client_credentials` grant we can publish the following bean:
  1333. .Customize Token Request Parameters for Client Credentials Grant
  1334. [tabs]
  1335. =====
  1336. Java::
  1337. +
  1338. [source,java,role="primary"]
  1339. ----
  1340. @Configuration
  1341. public class SecurityConfig {
  1342. @Bean
  1343. public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
  1344. OAuth2ClientCredentialsGrantRequestEntityConverter requestEntityConverter =
  1345. new OAuth2ClientCredentialsGrantRequestEntityConverter();
  1346. requestEntityConverter.addParametersConverter(parametersConverter());
  1347. DefaultClientCredentialsTokenResponseClient accessTokenResponseClient =
  1348. new DefaultClientCredentialsTokenResponseClient();
  1349. accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
  1350. return accessTokenResponseClient;
  1351. }
  1352. private static Converter<OAuth2ClientCredentialsGrantRequest, MultiValueMap<String, String>> parametersConverter() {
  1353. // ...
  1354. }
  1355. }
  1356. ----
  1357. Kotlin::
  1358. +
  1359. [source,kotlin,role="secondary"]
  1360. ----
  1361. @Configuration
  1362. class SecurityConfig {
  1363. @Bean
  1364. fun clientCredentialsAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> {
  1365. val requestEntityConverter = OAuth2ClientCredentialsGrantRequestEntityConverter()
  1366. requestEntityConverter.addParametersConverter(parametersConverter())
  1367. val accessTokenResponseClient = DefaultClientCredentialsTokenResponseClient()
  1368. accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter)
  1369. return accessTokenResponseClient
  1370. }
  1371. private fun parametersConverter(): Converter<OAuth2ClientCredentialsGrantRequest, MultiValueMap<String, String>> {
  1372. // ...
  1373. }
  1374. }
  1375. ----
  1376. =====
  1377. Spring Security automatically resolves the following generic types of `OAuth2AccessTokenResponseClient` beans:
  1378. * `OAuth2AuthorizationCodeGrantRequest` (see `DefaultAuthorizationCodeTokenResponseClient`)
  1379. * `OAuth2RefreshTokenGrantRequest` (see `DefaultRefreshTokenTokenResponseClient`)
  1380. * `OAuth2ClientCredentialsGrantRequest` (see `DefaultClientCredentialsTokenResponseClient`)
  1381. * `OAuth2PasswordGrantRequest` (see `DefaultPasswordTokenResponseClient`)
  1382. * `JwtBearerGrantRequest` (see `DefaultJwtBearerTokenResponseClient`)
  1383. * `TokenExchangeGrantRequest` (see `DefaultTokenExchangeTokenResponseClient`)
  1384. [TIP]
  1385. ====
  1386. Publishing a bean of type `OAuth2AccessTokenResponseClient<JwtBearerGrantRequest>` will automatically enable the `jwt-bearer` grant type without the need to <<oauth2-client-enable-extension-grant-type,configure it separately>>.
  1387. ====
  1388. [TIP]
  1389. ====
  1390. Publishing a bean of type `OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest>` will automatically enable the `token-exchange` grant type without the need to <<oauth2-client-enable-extension-grant-type,configure it separately>>.
  1391. ====
  1392. [[oauth2-client-customize-rest-operations]]
  1393. === Customize the `RestOperations` used by OAuth2 Client Components
  1394. Another common use case is the need to customize the `RestOperations` used when obtaining an access token.
  1395. We might need to do this to customize processing of the response (via a custom `HttpMessageConverter`) or to apply proxy settings for a corporate network (via a customized `ClientHttpRequestFactory`).
  1396. With Spring Security 6.2 and later, we can simply publish beans of type `OAuth2AccessTokenResponseClient` and Spring Security will configure and publish an `OAuth2AuthorizedClientManager` bean for us.
  1397. The following example customizes the `RestOperations` for all of the supported grant types:
  1398. .Customize `RestOperations` for OAuth2 Client
  1399. [tabs]
  1400. =====
  1401. Java::
  1402. +
  1403. [source,java,role="primary"]
  1404. ----
  1405. @Configuration
  1406. public class SecurityConfig {
  1407. @Bean
  1408. public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() {
  1409. DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
  1410. new DefaultAuthorizationCodeTokenResponseClient();
  1411. accessTokenResponseClient.setRestOperations(restTemplate());
  1412. return accessTokenResponseClient;
  1413. }
  1414. @Bean
  1415. public OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenAccessTokenResponseClient() {
  1416. DefaultRefreshTokenTokenResponseClient accessTokenResponseClient =
  1417. new DefaultRefreshTokenTokenResponseClient();
  1418. accessTokenResponseClient.setRestOperations(restTemplate());
  1419. return accessTokenResponseClient;
  1420. }
  1421. @Bean
  1422. public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
  1423. DefaultClientCredentialsTokenResponseClient accessTokenResponseClient =
  1424. new DefaultClientCredentialsTokenResponseClient();
  1425. accessTokenResponseClient.setRestOperations(restTemplate());
  1426. return accessTokenResponseClient;
  1427. }
  1428. @Bean
  1429. public OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordAccessTokenResponseClient() {
  1430. DefaultPasswordTokenResponseClient accessTokenResponseClient =
  1431. new DefaultPasswordTokenResponseClient();
  1432. accessTokenResponseClient.setRestOperations(restTemplate());
  1433. return accessTokenResponseClient;
  1434. }
  1435. @Bean
  1436. public OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() {
  1437. DefaultJwtBearerTokenResponseClient accessTokenResponseClient =
  1438. new DefaultJwtBearerTokenResponseClient();
  1439. accessTokenResponseClient.setRestOperations(restTemplate());
  1440. return accessTokenResponseClient;
  1441. }
  1442. @Bean
  1443. public OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> tokenExchangeAccessTokenResponseClient() {
  1444. DefaultTokenExchangeTokenResponseClient accessTokenResponseClient =
  1445. new DefaultTokenExchangeTokenResponseClient();
  1446. accessTokenResponseClient.setRestOperations(restTemplate());
  1447. return accessTokenResponseClient;
  1448. }
  1449. @Bean
  1450. public RestTemplate restTemplate() {
  1451. // ...
  1452. }
  1453. }
  1454. ----
  1455. Kotlin::
  1456. +
  1457. [source,kotlin,role="secondary"]
  1458. ----
  1459. @Configuration
  1460. class SecurityConfig {
  1461. @Bean
  1462. fun authorizationCodeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> {
  1463. val accessTokenResponseClient = DefaultAuthorizationCodeTokenResponseClient()
  1464. accessTokenResponseClient.setRestOperations(restTemplate())
  1465. return accessTokenResponseClient
  1466. }
  1467. @Bean
  1468. fun refreshTokenAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> {
  1469. val accessTokenResponseClient = DefaultRefreshTokenTokenResponseClient()
  1470. accessTokenResponseClient.setRestOperations(restTemplate())
  1471. return accessTokenResponseClient
  1472. }
  1473. @Bean
  1474. fun clientCredentialsAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> {
  1475. val accessTokenResponseClient = DefaultClientCredentialsTokenResponseClient()
  1476. accessTokenResponseClient.setRestOperations(restTemplate())
  1477. return accessTokenResponseClient
  1478. }
  1479. @Bean
  1480. fun passwordAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> {
  1481. val accessTokenResponseClient = DefaultPasswordTokenResponseClient()
  1482. accessTokenResponseClient.setRestOperations(restTemplate())
  1483. return accessTokenResponseClient
  1484. }
  1485. @Bean
  1486. fun jwtBearerAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> {
  1487. val accessTokenResponseClient = DefaultJwtBearerTokenResponseClient()
  1488. accessTokenResponseClient.setRestOperations(restTemplate())
  1489. return accessTokenResponseClient
  1490. }
  1491. @Bean
  1492. fun tokenExchangeAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<TokenExchangeGrantRequest> {
  1493. val accessTokenResponseClient = DefaultTokenExchangeTokenResponseClient()
  1494. accessTokenResponseClient.setRestOperations(restTemplate())
  1495. return accessTokenResponseClient
  1496. }
  1497. @Bean
  1498. fun restTemplate(): RestTemplate {
  1499. // ...
  1500. }
  1501. }
  1502. ----
  1503. =====
  1504. A default `OAuth2AuthorizedClientManager` will be published automatically by Spring Security when one is not already provided.
  1505. [TIP]
  1506. ====
  1507. Notice that we don't need to customize the `SecurityFilterChain` bean in this case, and can stick with the defaults.
  1508. If using Spring Boot with no additional customizations, we can actually omit the `SecurityFilterChain` bean entirely.
  1509. ====
  1510. Prior to Spring Security 6.2, we had to ensure this customization was applied to both OAuth2 Login (if we are using this feature) and OAuth2 Client components.
  1511. We had to use both the Spring Security DSL (for the `authorization_code` grant) and publish a bean of type `OAuth2AuthorizedClientManager` for other grant types.
  1512. To understand what is being configured behind the scenes, here's what the configuration might have looked like:
  1513. .Customize `RestOperations` for OAuth2 Client (prior to 6.2)
  1514. [tabs]
  1515. =====
  1516. Java::
  1517. +
  1518. [source,java,role="primary"]
  1519. ----
  1520. @Configuration
  1521. @EnableWebSecurity
  1522. public class SecurityConfig {
  1523. @Bean
  1524. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  1525. DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
  1526. new DefaultAuthorizationCodeTokenResponseClient();
  1527. accessTokenResponseClient.setRestOperations(restTemplate());
  1528. http
  1529. // ...
  1530. .oauth2Login((oauth2Login) -> oauth2Login
  1531. .tokenEndpoint((tokenEndpoint) -> tokenEndpoint
  1532. .accessTokenResponseClient(accessTokenResponseClient)
  1533. )
  1534. )
  1535. .oauth2Client((oauth2Client) -> oauth2Client
  1536. .authorizationCodeGrant((authorizationCode) -> authorizationCode
  1537. .accessTokenResponseClient(accessTokenResponseClient)
  1538. )
  1539. );
  1540. return http.build();
  1541. }
  1542. @Bean
  1543. public OAuth2AuthorizedClientManager authorizedClientManager(
  1544. ClientRegistrationRepository clientRegistrationRepository,
  1545. OAuth2AuthorizedClientRepository authorizedClientRepository) {
  1546. DefaultRefreshTokenTokenResponseClient refreshTokenAccessTokenResponseClient =
  1547. new DefaultRefreshTokenTokenResponseClient();
  1548. refreshTokenAccessTokenResponseClient.setRestOperations(restTemplate());
  1549. DefaultClientCredentialsTokenResponseClient clientCredentialsAccessTokenResponseClient =
  1550. new DefaultClientCredentialsTokenResponseClient();
  1551. clientCredentialsAccessTokenResponseClient.setRestOperations(restTemplate());
  1552. DefaultPasswordTokenResponseClient passwordAccessTokenResponseClient =
  1553. new DefaultPasswordTokenResponseClient();
  1554. passwordAccessTokenResponseClient.setRestOperations(restTemplate());
  1555. DefaultJwtBearerTokenResponseClient jwtBearerAccessTokenResponseClient =
  1556. new DefaultJwtBearerTokenResponseClient();
  1557. jwtBearerAccessTokenResponseClient.setRestOperations(restTemplate());
  1558. JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider =
  1559. new JwtBearerOAuth2AuthorizedClientProvider();
  1560. jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerAccessTokenResponseClient);
  1561. DefaultTokenExchangeTokenResponseClient tokenExchangeAccessTokenResponseClient =
  1562. new DefaultTokenExchangeTokenResponseClient();
  1563. tokenExchangeAccessTokenResponseClient.setRestOperations(restTemplate());
  1564. TokenExchangeOAuth2AuthorizedClientProvider tokenExchangeAuthorizedClientProvider =
  1565. new TokenExchangeOAuth2AuthorizedClientProvider();
  1566. tokenExchangeAuthorizedClientProvider.setAccessTokenResponseClient(tokenExchangeAccessTokenResponseClient);
  1567. OAuth2AuthorizedClientProvider authorizedClientProvider =
  1568. OAuth2AuthorizedClientProviderBuilder.builder()
  1569. .authorizationCode()
  1570. .refreshToken((refreshToken) -> refreshToken
  1571. .accessTokenResponseClient(refreshTokenAccessTokenResponseClient)
  1572. )
  1573. .clientCredentials((clientCredentials) -> clientCredentials
  1574. .accessTokenResponseClient(clientCredentialsAccessTokenResponseClient)
  1575. )
  1576. .password((password) -> password
  1577. .accessTokenResponseClient(passwordAccessTokenResponseClient)
  1578. )
  1579. .provider(jwtBearerAuthorizedClientProvider)
  1580. .provider(tokenExchangeAuthorizedClientProvider)
  1581. .build();
  1582. DefaultOAuth2AuthorizedClientManager authorizedClientManager =
  1583. new DefaultOAuth2AuthorizedClientManager(
  1584. clientRegistrationRepository, authorizedClientRepository);
  1585. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
  1586. return authorizedClientManager;
  1587. }
  1588. @Bean
  1589. public RestTemplate restTemplate() {
  1590. // ...
  1591. }
  1592. }
  1593. ----
  1594. Kotlin::
  1595. +
  1596. [source,kotlin,role="secondary"]
  1597. ----
  1598. import org.springframework.security.config.annotation.web.invoke
  1599. @Configuration
  1600. @EnableWebSecurity
  1601. class SecurityConfig {
  1602. @Bean
  1603. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  1604. val tokenResponseClient = DefaultAuthorizationCodeTokenResponseClient()
  1605. tokenResponseClient.setRestOperations(restTemplate())
  1606. http {
  1607. // ...
  1608. oauth2Login {
  1609. tokenEndpoint {
  1610. accessTokenResponseClient = tokenResponseClient
  1611. }
  1612. }
  1613. oauth2Client {
  1614. authorizationCodeGrant {
  1615. accessTokenResponseClient = tokenResponseClient
  1616. }
  1617. }
  1618. }
  1619. return http.build()
  1620. }
  1621. @Bean
  1622. fun authorizedClientManager(
  1623. clientRegistrationRepository: ClientRegistrationRepository?,
  1624. authorizedClientRepository: OAuth2AuthorizedClientRepository?
  1625. ): OAuth2AuthorizedClientManager {
  1626. val refreshTokenAccessTokenResponseClient = DefaultRefreshTokenTokenResponseClient()
  1627. refreshTokenAccessTokenResponseClient.setRestOperations(restTemplate())
  1628. val clientCredentialsAccessTokenResponseClient = DefaultClientCredentialsTokenResponseClient()
  1629. clientCredentialsAccessTokenResponseClient.setRestOperations(restTemplate())
  1630. val passwordAccessTokenResponseClient = DefaultPasswordTokenResponseClient()
  1631. passwordAccessTokenResponseClient.setRestOperations(restTemplate())
  1632. val jwtBearerAccessTokenResponseClient = DefaultJwtBearerTokenResponseClient()
  1633. jwtBearerAccessTokenResponseClient.setRestOperations(restTemplate())
  1634. val jwtBearerAuthorizedClientProvider = JwtBearerOAuth2AuthorizedClientProvider()
  1635. jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerAccessTokenResponseClient)
  1636. val tokenExchangeAccessTokenResponseClient = DefaultTokenExchangeTokenResponseClient()
  1637. tokenExchangeAccessTokenResponseClient.setRestOperations(restTemplate())
  1638. val tokenExchangeAuthorizedClientProvider = TokenExchangeOAuth2AuthorizedClientProvider()
  1639. tokenExchangeAuthorizedClientProvider.setAccessTokenResponseClient(tokenExchangeAccessTokenResponseClient)
  1640. val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
  1641. .authorizationCode()
  1642. .refreshToken { refreshToken ->
  1643. refreshToken.accessTokenResponseClient(refreshTokenAccessTokenResponseClient)
  1644. }
  1645. .clientCredentials { clientCredentials ->
  1646. clientCredentials.accessTokenResponseClient(clientCredentialsAccessTokenResponseClient)
  1647. }
  1648. .password { password ->
  1649. password.accessTokenResponseClient(passwordAccessTokenResponseClient)
  1650. }
  1651. .provider(jwtBearerAuthorizedClientProvider)
  1652. .provider(tokenExchangeAuthorizedClientProvider)
  1653. .build()
  1654. val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
  1655. clientRegistrationRepository, authorizedClientRepository
  1656. )
  1657. authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
  1658. return authorizedClientManager
  1659. }
  1660. @Bean
  1661. fun restTemplate(): RestTemplate {
  1662. // ...
  1663. }
  1664. }
  1665. ----
  1666. =====
  1667. [[further-reading]]
  1668. == Further Reading
  1669. This preceding sections introduced Spring Security's support for OAuth2 with examples for common scenarios.
  1670. You can read more about OAuth2 Client and Resource Server in the following sections of the reference documentation:
  1671. * xref:servlet/oauth2/login/index.adoc[]
  1672. * xref:servlet/oauth2/client/index.adoc[]
  1673. * xref:servlet/oauth2/resource-server/index.adoc[]