소스 검색

Document RestClient-based implementations

Closes gh-15938
Steve Riesenberg 10 달 전
부모
커밋
8982851355

+ 167 - 329
docs/modules/ROOT/pages/servlet/oauth2/client/authorization-grants.adoc

@@ -1,16 +1,18 @@
-[[oauth2Client-auth-grant-support]]
-= Authorization Grant Support
+[[oauth2-client-authorization-grants]]
+= [[oauth2Client-auth-grant-support]]Authorization Grant Support
+:spring-security-reference-base-url: https://docs.spring.io/spring-security/reference
 
 This section describes Spring Security's support for authorization grants.
 
-[[oauth2Client-auth-code-grant]]
-== Authorization Code
+[[oauth2-client-authorization-code]]
+== [[oauth2Client-auth-code-grant]]Authorization Code
 
 [NOTE]
 ====
 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.
 ====
 
+[[oauth2-client-authorization-code-authorization]]
 === Obtaining Authorization
 
 [NOTE]
@@ -18,8 +20,7 @@ See the OAuth 2.0 Authorization Framework for further details on the https://too
 See the https://tools.ietf.org/html/rfc6749#section-4.1.1[Authorization Request/Response] protocol flow for the Authorization Code grant.
 ====
 
-
-
+[[oauth2-client-authorization-code-authorization-request]]
 === Initiating the Authorization Request
 
 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.
@@ -70,7 +71,7 @@ spring:
             client-authentication-method: none
             authorization-grant-type: authorization_code
             redirect-uri: "{baseUrl}/authorized/okta"
-            ...
+            # ...
 ----
 
 Public Clients are supported by using https://tools.ietf.org/html/rfc7636[Proof Key for Code Exchange] (PKCE).
@@ -82,8 +83,8 @@ If the client is running in an untrusted environment (such as a native applicati
 [TIP]
 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())`.
 
-[[oauth2Client-auth-code-redirect-uri]]
-The `DefaultOAuth2AuthorizationRequestResolver` also supports `URI` template variables for the `redirect-uri` by using `UriComponentsBuilder`.
+[[oauth2-client-authorization-code-redirect-uri]]
+[[oauth2Client-auth-code-redirect-uri]]The `DefaultOAuth2AuthorizationRequestResolver` also supports `URI` template variables for the `redirect-uri` by using `UriComponentsBuilder`.
 
 The following configuration uses all the supported `URI` template variables:
 
@@ -95,9 +96,9 @@ spring:
       client:
         registration:
           okta:
-            ...
+            # ...
             redirect-uri: "{baseScheme}://{baseHost}{basePort}{basePath}/authorized/{registrationId}"
-            ...
+            # ...
 ----
 
 [NOTE]
@@ -108,6 +109,7 @@ spring:
 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].
 Doing so ensures that the `X-Forwarded-*` headers are used when expanding the `redirect-uri`.
 
+[[oauth2-client-authorization-code-authorization-request-resolver]]
 === Customizing the Authorization Request
 
 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.
@@ -197,7 +199,7 @@ class SecurityConfig {
     }
 
     private fun authorizationRequestResolver(
-            clientRegistrationRepository: ClientRegistrationRepository?): OAuth2AuthorizationRequestResolver? {
+            clientRegistrationRepository: ClientRegistrationRepository?): OAuth2AuthorizationRequestResolver {
         val authorizationRequestResolver = DefaultOAuth2AuthorizationRequestResolver(
                 clientRegistrationRepository, "/oauth2/authorization")
         authorizationRequestResolver.setAuthorizationRequestCustomizer(
@@ -269,7 +271,7 @@ private fun authorizationRequestCustomizer(): Consumer<OAuth2AuthorizationReques
 ----
 ======
 
-
+[[oauth2-client-authorization-code-authorization-request-repository]]
 === Storing the Authorization Request
 
 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).
@@ -300,14 +302,16 @@ public class OAuth2ClientSecurityConfig {
 			.oauth2Client(oauth2 -> oauth2
 				.authorizationCodeGrant(codeGrant -> codeGrant
 					.authorizationRequestRepository(this.authorizationRequestRepository())
-					...
+					// ...
 				)
+			)
             .oauth2Login(oauth2 -> oauth2
                 .authorizationEndpoint(endpoint -> endpoint
                     .authorizationRequestRepository(this.authorizationRequestRepository())
-                    ...
+                    // ...
                 )
-            ).build();
+            );
+			return http.build();
 	}
 
     @Bean
@@ -351,6 +355,7 @@ Xml::
 ----
 ======
 
+[[oauth2-client-authorization-code-access-token]]
 === Requesting an Access Token
 
 [NOTE]
@@ -358,73 +363,35 @@ Xml::
 See the https://tools.ietf.org/html/rfc6749#section-4.1.3[Access Token Request/Response] protocol flow for the Authorization Code grant.
 ====
 
-The default implementation of `OAuth2AccessTokenResponseClient` for the Authorization Code grant is `DefaultAuthorizationCodeTokenResponseClient`, which uses a `RestOperations` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
-
-The `DefaultAuthorizationCodeTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request and/or post-handling of the Token Response.
-
-
-=== Customizing the Access Token Request
+There are two implementations of `OAuth2AccessTokenResponseClient` that can be used to make HTTP requests to the Token Endpoint in order to obtain an access token for the Authorization Code grant:
 
-If you need to customize the pre-processing of the Token Request, you can provide `DefaultAuthorizationCodeTokenResponseClient.setRequestEntityConverter()` with a custom `Converter<OAuth2AuthorizationCodeGrantRequest, RequestEntity<?>>`.
-The default implementation (`OAuth2AuthorizationCodeGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.1.3[OAuth 2.0 Access Token Request].
-However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s).
+* `DefaultAuthorizationCodeTokenResponseClient` (_default_)
+* `RestClientAuthorizationCodeTokenResponseClient`
 
-To customize only the parameters of the request, you can provide `OAuth2AuthorizationCodeGrantRequestEntityConverter.setParametersConverter()` with a custom `Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>>` to completely override the parameters sent with the request. This is often simpler than constructing a `RequestEntity` directly.
+The default implementation uses a `RestOperations` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
+Spring Security 6.4 introduces a new implementation based on `RestClient`, which provides similar functionality but is better aligned with the Reactive version of the component (based on `WebClient`) in order to provide consistent configuration for applications on either stack.
 
-[TIP]
+[NOTE]
 ====
-If you prefer to only add additional parameters, you can provide `OAuth2AuthorizationCodeGrantRequestEntityConverter.addParametersConverter()` with a custom `Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>>` which constructs an aggregate `Converter`.
+This section focuses on `RestClientAuthorizationCodeTokenResponseClient`.
+You can read about {spring-security-reference-base-url}/6.3/servlet/oauth2/client/authorization-grants.html#_requesting_an_access_token[`DefaultAuthorizationCodeTokenResponseClient`] in the Spring Security 6.3 documentation.
 ====
 
-[IMPORTANT]
-====
-The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider.
-====
+:section-id: authorization-code
+:grant-type: Authorization Code
+:class-name: RestClientAuthorizationCodeTokenResponseClient
+:grant-request: OAuth2AuthorizationCodeGrantRequest
+:leveloffset: +1
+include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
 
-=== Customizing the Access Token Response
+:leveloffset: -1
 
-On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultAuthorizationCodeTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`.
-The default `RestOperations` is configured as follows:
+[[oauth2-client-authorization-code-access-token-response-client-dsl]]
+=== Customize using the DSL
 
-[tabs]
-======
-Java::
-+
-[source,java,role="primary"]
-----
-RestTemplate restTemplate = new RestTemplate(Arrays.asList(
-		new FormHttpMessageConverter(),
-		new OAuth2AccessTokenResponseHttpMessageConverter()));
+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:
 
-restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
-----
-
-Kotlin::
-+
-[source,kotlin,role="secondary"]
-----
-val restTemplate = RestTemplate(listOf(
-        FormHttpMessageConverter(),
-        OAuth2AccessTokenResponseHttpMessageConverter()))
-
-restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler()
-----
-======
-
-[TIP]
-====
-Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request.
-====
-
-`OAuth2AccessTokenResponseHttpMessageConverter` is an `HttpMessageConverter` for an OAuth 2.0 Access Token Response.
-You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setAccessTokenResponseConverter()` with a custom `Converter<Map<String, Object>, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`.
-
-`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`.
-It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`.
-
-Whether you customize `DefaultAuthorizationCodeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows:
-
-.Access Token Response Configuration
+.Access Token Response Configuration via DSL
 [tabs]
 ======
 Java::
@@ -441,7 +408,7 @@ public class OAuth2ClientSecurityConfig {
 			.oauth2Client(oauth2 -> oauth2
 				.authorizationCodeGrant(codeGrant -> codeGrant
 					.accessTokenResponseClient(this.accessTokenResponseClient())
-					...
+					// ...
 				)
 			);
 		return http.build();
@@ -483,16 +450,15 @@ Xml::
 ----
 ======
 
-
-[[oauth2Client-refresh-token-grant]]
-== Refresh Token
+[[oauth2-client-refresh-token]]
+== [[oauth2Client-refresh-token-grant]]Refresh Token
 
 [NOTE]
 ====
 See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.5[Refresh Token].
 ====
 
-
+[[oauth2-client-refresh-token-access-token]]
 === Refreshing an Access Token
 
 [NOTE]
@@ -500,72 +466,33 @@ See the OAuth 2.0 Authorization Framework for further details on the https://too
 See the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant.
 ====
 
-The default implementation of `OAuth2AccessTokenResponseClient` for the Refresh Token grant is `DefaultRefreshTokenTokenResponseClient`, which uses a `RestOperations` when refreshing an access token at the Authorization Server’s Token Endpoint.
+There are two implementations of `OAuth2AccessTokenResponseClient` that can be used to make HTTP requests to the Token Endpoint in order to obtain an access token for the Refresh Token grant:
 
-The `DefaultRefreshTokenTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response.
+* `DefaultRefreshTokenTokenResponseClient` (_default_)
+* `RestClientRefreshTokenTokenResponseClient`
 
+The default implementation uses a `RestOperations` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
+Spring Security 6.4 introduces a new implementation based on `RestClient`, which provides similar functionality but is better aligned with the Reactive version of the component (based on `WebClient`) in order to provide consistent configuration for applications on either stack.
 
-=== Customizing the Access Token Request
-
-If you need to customize the pre-processing of the Token Request, you can provide `DefaultRefreshTokenTokenResponseClient.setRequestEntityConverter()` with a custom `Converter<OAuth2RefreshTokenGrantRequest, RequestEntity<?>>`.
-The default implementation (`OAuth2RefreshTokenGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-6[OAuth 2.0 Access Token Request].
-However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s).
-
-To customize only the parameters of the request, you can provide `OAuth2RefreshTokenGrantRequestEntityConverter.setParametersConverter()` with a custom `Converter<OAuth2RefreshTokenGrantRequest, MultiValueMap<String, String>>` to completely override the parameters sent with the request. This is often simpler than constructing a `RequestEntity` directly.
-
-[TIP]
-====
-If you prefer to only add additional parameters, you can provide `OAuth2RefreshTokenGrantRequestEntityConverter.addParametersConverter()` with a custom `Converter<OAuth2RefreshTokenGrantRequest, MultiValueMap<String, String>>` which constructs an aggregate `Converter`.
-====
-
-[IMPORTANT]
+[NOTE]
 ====
-The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider.
+This section focuses on `RestClientRefreshTokenTokenResponseClient`.
+You can read about {spring-security-reference-base-url}/6.3/servlet/oauth2/client/authorization-grants.html#_refreshing_an_access_token[`DefaultRefreshTokenTokenResponseClient`] in the Spring Security 6.3 documentation.
 ====
 
+:section-id: refresh-token
+:grant-type: Refresh Token
+:class-name: RestClientRefreshTokenTokenResponseClient
+:grant-request: OAuth2RefreshTokenGrantRequest
+:leveloffset: +1
+include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
 
-=== Customizing the Access Token Response
+:leveloffset: -1
 
-On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultRefreshTokenTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`.
-The default `RestOperations` is configured as follows:
+[[oauth2-client-refresh-token-authorized-client-provider-builder]]
+=== Customize using the Builder
 
-[tabs]
-======
-Java::
-+
-[source,java,role="primary"]
-----
-RestTemplate restTemplate = new RestTemplate(Arrays.asList(
-		new FormHttpMessageConverter(),
-		new OAuth2AccessTokenResponseHttpMessageConverter()));
-
-restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
-----
-
-Kotlin::
-+
-[source,kotlin,role="secondary"]
-----
-val restTemplate = RestTemplate(listOf(
-        FormHttpMessageConverter(),
-        OAuth2AccessTokenResponseHttpMessageConverter()))
-
-restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler()
-----
-======
-
-[TIP]
-====
-Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request.
-====
-
-`OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response.
-You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setAccessTokenResponseConverter()` with a custom `Converter<Map<String, Object>, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`.
-
-`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`.
-It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`.
-
-Whether you customize `DefaultRefreshTokenTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows:
+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:
 
 [tabs]
 ======
@@ -582,7 +509,7 @@ OAuth2AuthorizedClientProvider authorizedClientProvider =
 				.refreshToken(configurer -> configurer.accessTokenResponseClient(refreshTokenTokenResponseClient))
 				.build();
 
-...
+// ...
 
 authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
 ----
@@ -599,7 +526,7 @@ val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
         .refreshToken { it.accessTokenResponseClient(refreshTokenTokenResponseClient) }
         .build()
 
-...
+// ...
 
 authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
 ----
@@ -614,14 +541,15 @@ which is an implementation of an `OAuth2AuthorizedClientProvider` for the Refres
 The `OAuth2RefreshToken` can optionally be returned in the Access Token Response for the `authorization_code` and `password` grant types.
 If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2AuthorizedClient.getAccessToken()` is expired, it is automatically refreshed by the `RefreshTokenOAuth2AuthorizedClientProvider`.
 
-
-[[oauth2Client-client-creds-grant]]
-== Client Credentials
+[[oauth2-client-client-credentials]]
+== [[oauth2Client-client-creds-grant]]Client Credentials
 
 [NOTE]
+====
 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.
+====
 
-
+[[oauth2-client-client-credentials-access-token]]
 === Requesting an Access Token
 
 [NOTE]
@@ -629,72 +557,33 @@ Please refer to the OAuth 2.0 Authorization Framework for further details on the
 See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials] grant.
 ====
 
-The default implementation of `OAuth2AccessTokenResponseClient` for the Client Credentials grant is `DefaultClientCredentialsTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint.
-
-The `DefaultClientCredentialsTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response.
-
-
-=== Customizing the Access Token Request
+There are two implementations of `OAuth2AccessTokenResponseClient` that can be used to make HTTP requests to the Token Endpoint in order to obtain an access token for the Client Credentials grant:
 
-If you need to customize the pre-processing of the Token Request, you can provide `DefaultClientCredentialsTokenResponseClient.setRequestEntityConverter()` with a custom `Converter<OAuth2ClientCredentialsGrantRequest, RequestEntity<?>>`.
-The default implementation (`OAuth2ClientCredentialsGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.4.2[OAuth 2.0 Access Token Request].
-However, providing a custom `Converter` would let you extend the standard Token Request and add custom parameter(s).
+* `DefaultClientCredentialsTokenResponseClient` (_default_)
+* `RestClientClientCredentialsTokenResponseClient`
 
-To customize only the parameters of the request, you can provide `OAuth2ClientCredentialsGrantRequestEntityConverter.setParametersConverter()` with a custom `Converter<OAuth2ClientCredentialsGrantRequest, MultiValueMap<String, String>>` to completely override the parameters sent with the request. This is often simpler than constructing a `RequestEntity` directly.
+The default implementation uses a `RestOperations` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
+Spring Security 6.4 introduces a new implementation based on `RestClient`, which provides similar functionality but is better aligned with the Reactive version of the component (based on `WebClient`) in order to provide consistent configuration for applications on either stack.
 
-[TIP]
+[NOTE]
 ====
-If you prefer to only add additional parameters, you can provide `OAuth2ClientCredentialsGrantRequestEntityConverter.addParametersConverter()` with a custom `Converter<OAuth2ClientCredentialsGrantRequest, MultiValueMap<String, String>>` which constructs an aggregate `Converter`.
+This section focuses on `RestClientClientCredentialsTokenResponseClient`.
+You can read about {spring-security-reference-base-url}/6.3/servlet/oauth2/client/authorization-grants.html#_requesting_an_access_token_2[`DefaultClientCredentialsTokenResponseClient`] in the Spring Security 6.3 documentation.
 ====
 
-[IMPORTANT]
-====
-The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider.
-====
+:section-id: client-credentials
+:grant-type: Client Credentials
+:class-name: RestClientClientCredentialsTokenResponseClient
+:grant-request: OAuth2ClientCredentialsGrantRequest
+:leveloffset: +1
+include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
 
+:leveloffset: -1
 
-=== Customizing the Access Token Response
+[[oauth2-client-client-credentials-authorized-client-provider-builder]]
+=== Customize using the Builder
 
-On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultClientCredentialsTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`.
-The default `RestOperations` is configured as follows:
-
-[tabs]
-======
-Java::
-+
-[source,java,role="primary"]
-----
-RestTemplate restTemplate = new RestTemplate(Arrays.asList(
-		new FormHttpMessageConverter(),
-		new OAuth2AccessTokenResponseHttpMessageConverter()));
-
-restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
-----
-
-Kotlin::
-+
-[source,kotlin,role="secondary"]
-----
-val restTemplate = RestTemplate(listOf(
-        FormHttpMessageConverter(),
-        OAuth2AccessTokenResponseHttpMessageConverter()))
-
-restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler()
-----
-======
-
-[TIP]
-====
-Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request.
-====
-
-`OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response.
-You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setAccessTokenResponseConverter()` with a custom `Converter<Map<String, Object>, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`.
-
-`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`.
-It uses an `OAuth2ErrorHttpMessageConverter` to convert the OAuth 2.0 Error parameters to an `OAuth2Error`.
-
-Whether you customize `DefaultClientCredentialsTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows:
+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:
 
 [tabs]
 ======
@@ -710,7 +599,7 @@ OAuth2AuthorizedClientProvider authorizedClientProvider =
 				.clientCredentials(configurer -> configurer.accessTokenResponseClient(clientCredentialsTokenResponseClient))
 				.build();
 
-...
+// ...
 
 authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
 ----
@@ -726,7 +615,7 @@ val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
         .clientCredentials { it.accessTokenResponseClient(clientCredentialsTokenResponseClient) }
         .build()
 
-...
+// ...
 
 authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
 ----
@@ -738,6 +627,7 @@ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
 which is an implementation of an `OAuth2AuthorizedClientProvider` for the Client Credentials grant.
 ====
 
+[[oauth2-client-client-credentials-authorized-client-manager]]
 === Using the Access Token
 
 Consider the following Spring Boot properties for an OAuth 2.0 Client registration:
@@ -835,7 +725,7 @@ public class OAuth2ClientController {
 
 		OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
 
-		...
+		// ...
 
 		return "index";
 	}
@@ -865,7 +755,7 @@ class OAuth2ClientController {
         val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
         val accessToken: OAuth2AccessToken = authorizedClient.accessToken
 
-        ...
+        // ...
 
         return "index"
     }
@@ -879,14 +769,15 @@ class OAuth2ClientController {
 If not provided, they default to `ServletRequestAttributes` by using `RequestContextHolder.getRequestAttributes()`.
 ====
 
-[[oauth2Client-password-grant]]
-== Resource Owner Password Credentials
+[[oauth2-client-password]]
+== [[oauth2Client-password-grant]]Resource Owner Password Credentials
 
 [NOTE]
 ====
 See the OAuth 2.0 Authorization Framework for further details on the https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials] grant.
 ====
 
+[[oauth2-client-password-access-token]]
 === Requesting an Access Token
 
 [NOTE]
@@ -896,8 +787,15 @@ See the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/R
 
 The default implementation of `OAuth2AccessTokenResponseClient` for the Resource Owner Password Credentials grant is `DefaultPasswordTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint.
 
+[CAUTION]
+====
+The `DefaultPasswordTokenResponseClient` class and support for the Resource Owner Password Credentials grant are deprecated.
+This section will be removed in Spring Security 7.
+====
+
 The `DefaultPasswordTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response.
 
+[[oauth2-client-password-access-token-request]]
 === Customizing the Access Token Request
 
 If you need to customize the pre-processing of the Token Request, you can provide `DefaultPasswordTokenResponseClient.setRequestEntityConverter()` with a custom `Converter<OAuth2PasswordGrantRequest, RequestEntity<?>>`.
@@ -916,7 +814,7 @@ If you prefer to only add additional parameters, you can provide `OAuth2Password
 The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider.
 ====
 
-
+[[oauth2-client-password-access-token-response]]
 === Customizing the Access Token Response
 
 On the other end, if you need to customize the post-handling of the Token Response, you need to provide `DefaultPasswordTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`.
@@ -958,6 +856,9 @@ You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseC
 `OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`.
 It uses an `OAuth2ErrorHttpMessageConverter` to convert the OAuth 2.0 Error parameters to an `OAuth2Error`.
 
+[[oauth2-client-password-authorized-client-provider-builder]]
+=== Customize using the Builder
+
 Whether you customize `DefaultPasswordTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you need to configure it as follows:
 
 [tabs]
@@ -975,7 +876,7 @@ OAuth2AuthorizedClientProvider authorizedClientProvider =
 				.refreshToken()
 				.build();
 
-...
+// ...
 
 authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
 ----
@@ -991,7 +892,7 @@ val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
         .refreshToken()
         .build()
 
-...
+// ...
 
 authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
 ----
@@ -1003,6 +904,7 @@ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
 which is an implementation of an `OAuth2AuthorizedClientProvider` for the Resource Owner Password Credentials grant.
 ====
 
+[[oauth2-client-password-authorized-client-manager]]
 === Using the Access Token
 
 Consider the following Spring Boot properties for an OAuth 2.0 Client registration:
@@ -1144,7 +1046,7 @@ public class OAuth2ClientController {
 
 		OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
 
-		...
+		// ...
 
 		return "index";
 	}
@@ -1174,7 +1076,7 @@ class OAuth2ClientController {
         val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
         val accessToken: OAuth2AccessToken = authorizedClient.accessToken
 
-        ...
+        // ...
 
         return "index"
     }
@@ -1188,16 +1090,15 @@ class OAuth2ClientController {
 If not provided, they default to `ServletRequestAttributes` using `RequestContextHolder.getRequestAttributes()`.
 ====
 
-
-[[oauth2Client-jwt-bearer-grant]]
-== JWT Bearer
+[[oauth2-client-jwt-bearer]]
+== [[oauth2Client-jwt-bearer-grant]]JWT Bearer
 
 [NOTE]
 ====
 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.
 ====
 
-
+[[oauth2-client-jwt-bearer-access-token]]
 === Requesting an Access Token
 
 [NOTE]
@@ -1205,65 +1106,33 @@ Please refer to JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication
 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.
 ====
 
-The default implementation of `OAuth2AccessTokenResponseClient` for the JWT Bearer grant is `DefaultJwtBearerTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint.
-
-The `DefaultJwtBearerTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response.
-
-
-=== Customizing the Access Token Request
-
-If you need to customize the pre-processing of the Token Request, you can provide `DefaultJwtBearerTokenResponseClient.setRequestEntityConverter()` with a custom `Converter<JwtBearerGrantRequest, RequestEntity<?>>`.
-The default implementation `JwtBearerGrantRequestEntityConverter` builds a `RequestEntity` representation of a https://datatracker.ietf.org/doc/html/rfc7523#section-2.1[OAuth 2.0 Access Token Request].
-However, providing a custom `Converter`, would allow you to extend the Token Request and add custom parameter(s).
-
-To customize only the parameters of the request, you can provide `JwtBearerGrantRequestEntityConverter.setParametersConverter()` with a custom `Converter<JwtBearerGrantRequest, MultiValueMap<String, String>>` to completely override the parameters sent with the request. This is often simpler than constructing a `RequestEntity` directly.
-
-[TIP]
-If you prefer to only add additional parameters, you can provide `JwtBearerGrantRequestEntityConverter.addParametersConverter()` with a custom `Converter<JwtBearerGrantRequest, MultiValueMap<String, String>>` which constructs an aggregate `Converter`.
-
+There are two implementations of `OAuth2AccessTokenResponseClient` that can be used to make HTTP requests to the Token Endpoint in order to obtain an access token for the JWT Bearer grant:
 
-=== Customizing the Access Token Response
+* `DefaultJwtBearerTokenResponseClient` (_default_)
+* `RestClientJwtBearerTokenResponseClient`
 
-On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultJwtBearerTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`.
-The default `RestOperations` is configured as follows:
+The default implementation uses a `RestOperations` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
+Spring Security 6.4 introduces a new implementation based on `RestClient`, which provides similar functionality but is better aligned with the Reactive version of the component (based on `WebClient`) in order to provide consistent configuration for applications on either stack.
 
-[tabs]
-======
-Java::
-+
-[source,java,role="primary"]
-----
-RestTemplate restTemplate = new RestTemplate(Arrays.asList(
-		new FormHttpMessageConverter(),
-		new OAuth2AccessTokenResponseHttpMessageConverter()));
-
-restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
-----
-
-Kotlin::
-+
-[source,kotlin,role="secondary"]
-----
-val restTemplate = RestTemplate(listOf(
-        FormHttpMessageConverter(),
-        OAuth2AccessTokenResponseHttpMessageConverter()))
-
-restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler()
-----
-======
-
-[TIP]
+[NOTE]
 ====
-Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request.
+This section focuses on `RestClientJwtBearerTokenResponseClient`.
+You can read about {spring-security-reference-base-url}/6.3/servlet/oauth2/client/authorization-grants.html#_requesting_an_access_token_4[`DefaultClientCredentialsTokenResponseClient`] in the Spring Security 6.3 documentation.
 ====
 
-`OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response.
-You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setAccessTokenResponseConverter()` with a custom `Converter<Map<String, Object>, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`.
+:section-id: jwt-bearer
+:grant-type: JWT Bearer
+:class-name: RestClientJwtBearerTokenResponseClient
+:grant-request: JwtBearerGrantRequest
+:leveloffset: +1
+include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
+
+:leveloffset: -1
 
-`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request.
-It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`.
+[[oauth2-client-jwt-bearer-authorized-client-provider-builder]]
+=== Customize using the Builder
 
-Whether you customize `DefaultJwtBearerTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example:
+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:
 
 [tabs]
 ======
@@ -1282,7 +1151,7 @@ OAuth2AuthorizedClientProvider authorizedClientProvider =
 				.provider(jwtBearerAuthorizedClientProvider)
 				.build();
 
-...
+// ...
 
 authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
 ----
@@ -1295,18 +1164,19 @@ Kotlin::
 val jwtBearerTokenResponseClient: OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> = ...
 
 val jwtBearerAuthorizedClientProvider = JwtBearerOAuth2AuthorizedClientProvider()
-jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerTokenResponseClient);
+jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerTokenResponseClient)
 
 val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
         .provider(jwtBearerAuthorizedClientProvider)
         .build()
 
-...
+// ...
 
 authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
 ----
 ======
 
+[[oauth2-client-jwt-bearer-authorized-client-manager]]
 === Using the Access Token
 
 Given the following Spring Boot properties for an OAuth 2.0 Client registration:
@@ -1400,7 +1270,7 @@ public class OAuth2ResourceServerController {
 		OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
 		OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
 
-		...
+		// ...
 
 	}
 }
@@ -1423,7 +1293,7 @@ class OAuth2ResourceServerController {
         val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
         val accessToken: OAuth2AccessToken = authorizedClient.accessToken
 
-        ...
+        // ...
 
     }
 }
@@ -1436,15 +1306,15 @@ class OAuth2ResourceServerController {
 [TIP]
 If you need to resolve the `Jwt` assertion from a different source, you can provide `JwtBearerOAuth2AuthorizedClientProvider.setJwtAssertionResolver()` with a custom `Function<OAuth2AuthorizationContext, Jwt>`.
 
-[[oauth2Client-token-exchange-grant]]
-== Token Exchange
+[[oauth2-client-token-exchange]]
+== [[oauth2Client-token-exchange-grant]]Token Exchange
 
 [NOTE]
 ====
 Please refer to OAuth 2.0 Token Exchange for further details on the https://datatracker.ietf.org/doc/html/rfc8693[Token Exchange] grant.
 ====
 
-
+[[oauth2-client-token-exchange-access-token]]
 === Requesting an Access Token
 
 [NOTE]
@@ -1452,65 +1322,33 @@ Please refer to OAuth 2.0 Token Exchange for further details on the https://data
 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.
 ====
 
-The default implementation of `OAuth2AccessTokenResponseClient` for the Token Exchange grant is `DefaultTokenExchangeTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint.
-
-The `DefaultTokenExchangeTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response.
-
-
-=== Customizing the Access Token Request
-
-If you need to customize the pre-processing of the Token Request, you can provide `DefaultTokenExchangeTokenResponseClient.setRequestEntityConverter()` with a custom `Converter<TokenExchangeGrantRequest, RequestEntity<?>>`.
-The default implementation `TokenExchangeGrantRequestEntityConverter` builds a `RequestEntity` representation of a https://datatracker.ietf.org/doc/html/rfc8693#section-2.1[OAuth 2.0 Access Token Request].
-However, providing a custom `Converter`, would allow you to extend the Token Request and add custom parameter(s).
-
-To customize only the parameters of the request, you can provide `TokenExchangeGrantRequestEntityConverter.setParametersConverter()` with a custom `Converter<TokenExchangeGrantRequest, MultiValueMap<String, String>>` to completely override the parameters sent with the request. This is often simpler than constructing a `RequestEntity` directly.
-
-[TIP]
-If you prefer to only add additional parameters, you can provide `TokenExchangeGrantRequestEntityConverter.addParametersConverter()` with a custom `Converter<TokenExchangeGrantRequest, MultiValueMap<String, String>>` which constructs an aggregate `Converter`.
-
-
-=== Customizing the Access Token Response
-
-On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultTokenExchangeTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`.
-The default `RestOperations` is configured as follows:
-
-[tabs]
-======
-Java::
-+
-[source,java,role="primary"]
-----
-RestTemplate restTemplate = new RestTemplate(Arrays.asList(
-		new FormHttpMessageConverter(),
-		new OAuth2AccessTokenResponseHttpMessageConverter()));
-
-restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
-----
+There are two implementations of `OAuth2AccessTokenResponseClient` that can be used to make HTTP requests to the Token Endpoint in order to obtain an access token for the Token Exchange grant:
 
-Kotlin::
-+
-[source,kotlin,role="secondary"]
-----
-val restTemplate = RestTemplate(listOf(
-        FormHttpMessageConverter(),
-        OAuth2AccessTokenResponseHttpMessageConverter()))
+* `DefaultTokenExchangeTokenResponseClient` (_default_)
+* `RestClientTokenExchangeTokenResponseClient`
 
-restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler()
-----
-======
+The default implementation uses a `RestOperations` instance to exchange an authorization code for an access token at the Authorization Server’s Token Endpoint.
+Spring Security 6.4 introduces a new implementation based on `RestClient`, which provides similar functionality but is better aligned with the Reactive version of the component (based on `WebClient`) in order to provide consistent configuration for applications on either stack.
 
-[TIP]
+[NOTE]
 ====
-Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request.
+This section focuses on `RestClientTokenExchangeTokenResponseClient`.
+You can read about {spring-security-reference-base-url}/6.3/servlet/oauth2/client/authorization-grants.html#_requesting_an_access_token_5[`DefaultTokenExchangeTokenResponseClient`] in the Spring Security 6.3 documentation.
 ====
 
-`OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response.
-You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setAccessTokenResponseConverter()` with a custom `Converter<Map<String, Object>, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`.
+:section-id: token-exchange
+:grant-type: Token Exchange
+:class-name: RestClientTokenExchangeTokenResponseClient
+:grant-request: TokenExchangeGrantRequest
+:leveloffset: +1
+include::partial$servlet/oauth2/client/rest-client-access-token-response-client.adoc[]
+
+:leveloffset: -1
 
-`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request.
-It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`.
+[[oauth2-client-token-exchange-authorized-client-provider-builder]]
+=== Customize using the Builder
 
-Whether you customize `DefaultTokenExchangeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example:
+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:
 
 [tabs]
 ======
@@ -1529,7 +1367,7 @@ OAuth2AuthorizedClientProvider authorizedClientProvider =
 				.provider(tokenExchangeAuthorizedClientProvider)
 				.build();
 
-...
+// ...
 
 authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
 ----
@@ -1548,14 +1386,14 @@ val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
         .provider(tokenExchangeAuthorizedClientProvider)
         .build()
 
-...
+// ...
 
 authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
 ----
 ======
 
-[[token-exchange-grant-access-token]]
-=== Using the Access Token
+[[oauth2-client-token-exchange-authorized-client-manager]]
+=== [[token-exchange-grant-access-token]]Using the Access Token
 
 Given the following Spring Boot properties for an OAuth 2.0 Client registration:
 
@@ -1648,7 +1486,7 @@ public class OAuth2ResourceServerController {
 		OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
 		OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
 
-		...
+		// ...
 
 	}
 }
@@ -1671,7 +1509,7 @@ class OAuth2ResourceServerController {
         val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
         val accessToken: OAuth2AccessToken = authorizedClient.accessToken
 
-        ...
+        // ...
 
     }
 }

+ 8 - 8
docs/modules/ROOT/pages/servlet/oauth2/client/authorized-clients.adoc

@@ -1,11 +1,10 @@
-[[oauth2Client-additional-features]]
-= Authorized Client Features
+[[oauth2-client-additional-features]]
+= [[oauth2Client-additional-features]]Authorized Client Features
 
 This section covers additional features provided by Spring Security for the OAuth2 client.
 
-
-[[oauth2Client-registered-authorized-client]]
-== Resolving an Authorized Client
+[[oauth2-client-registered-authorized-client]]
+== [[oauth2Client-registered-authorized-client]]Resolving an Authorized Client
 
 The `@RegisteredOAuth2AuthorizedClient` annotation provides the ability to resolve a method parameter to an argument value of type `OAuth2AuthorizedClient`.
 This is a convenient alternative compared to accessing the `OAuth2AuthorizedClient` by using the `OAuth2AuthorizedClientManager` or `OAuth2AuthorizedClientService`.
@@ -496,8 +495,8 @@ class RestClientConfig {
 ----
 =====
 
-[[oauth2Client-webclient-servlet]]
-== WebClient Integration for Servlet Environments
+[[oauth2-client-web-client]]
+== [[oauth2Client-webclient-servlet]]WebClient Integration for Servlet Environments
 
 The OAuth 2.0 Client support integrates with `WebClient` by using an `ExchangeFilterFunction`.
 
@@ -542,6 +541,7 @@ fun webClient(authorizedClientManager: OAuth2AuthorizedClientManager?): WebClien
 ----
 ======
 
+[[oauth2-client-web-client-authorized-client]]
 === Providing the Authorized Client
 
 The `ServletOAuth2AuthorizedClientExchangeFilterFunction` determines the client to use (for a request) by resolving the `OAuth2AuthorizedClient` from the `ClientRequest.attributes()` (request attributes).
@@ -702,7 +702,7 @@ fun index(): String {
 [WARNING]
 It is recommended to be cautious with this feature since all HTTP requests will receive an access token bound to the provided principal.
 
-
+[[oauth2-client-web-client-default-authorized-client]]
 === Defaulting the Authorized Client
 
 If neither `OAuth2AuthorizedClient` or `ClientRegistration.getRegistrationId()` is provided as a request attribute, the `ServletOAuth2AuthorizedClientExchangeFilterFunction` can determine the _default_ client to use, depending on its configuration.

+ 8 - 8
docs/modules/ROOT/pages/servlet/oauth2/client/client-authentication.adoc

@@ -1,8 +1,8 @@
-[[oauth2Client-client-auth-support]]
-= Client Authentication Support
+[[oauth2-client-authentication]]
+= [[oauth2Client-client-auth-support]]Client Authentication Support
 
-[[oauth2Client-client-credentials-auth]]
-== Client Credentials
+[[oauth2-client-client-credentials-authentication]]
+== [[oauth2Client-client-credentials-auth]]Client Credentials
 
 === Authenticate using `client_secret_basic`
 
@@ -83,8 +83,8 @@ spring:
             ...
 ----
 
-[[oauth2Client-jwt-bearer-auth]]
-== JWT Bearer
+[[oauth2-client-jwt-bearer-authentication]]
+== [[oauth2Client-jwt-bearer-auth]]JWT Bearer
 
 [NOTE]
 Please refer to JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants for further details on https://datatracker.ietf.org/doc/html/rfc7523#section-2.2[JWT Bearer] Client Authentication.
@@ -285,8 +285,8 @@ converter.setJwtClientAssertionCustomizer { context ->
 ----
 ======
 
-[[oauth2Client-public-auth]]
-== Public Authentication
+[[oauth2-client-public-authentication]]
+== [[oauth2Client-public-auth]]Public Authentication
 
 Public Client Authentication is supported out of the box and no customization is necessary to enable it.
 

+ 12 - 12
docs/modules/ROOT/pages/servlet/oauth2/client/index.adoc

@@ -1,5 +1,5 @@
-[[oauth2client]]
-= OAuth 2.0 Client
+[[oauth2-client]]
+= [[oauth2client]]OAuth 2.0 Client
 :page-section-summary-toc: 1
 
 The OAuth 2.0 Client features provide support for the Client role as defined in the https://tools.ietf.org/html/rfc6749#section-1.1[OAuth 2.0 Authorization Framework].
@@ -7,19 +7,19 @@ The OAuth 2.0 Client features provide support for the Client role as defined in
 At a high-level, the core features available are:
 
 .Authorization Grant support
-* https://tools.ietf.org/html/rfc6749#section-1.3.1[Authorization Code]
-* https://tools.ietf.org/html/rfc6749#section-6[Refresh Token]
-* https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials]
-* https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials]
-* https://datatracker.ietf.org/doc/html/rfc7523#section-2.1[JWT Bearer]
-* https://datatracker.ietf.org/doc/html/rfc8693#section-2.1[Token Exchange]
+* xref:servlet/oauth2/client/authorization-grants.adoc#oauth2-client-authorization-code[Authorization Code]
+* xref:servlet/oauth2/client/authorization-grants.adoc#oauth2-client-refresh-token[Refresh Token]
+* xref:servlet/oauth2/client/authorization-grants.adoc#oauth2-client-client-credentials[Client Credentials]
+* xref:servlet/oauth2/client/authorization-grants.adoc#oauth2-client-password[Resource Owner Password Credentials]
+* xref:servlet/oauth2/client/authorization-grants.adoc#oauth2-client-jwt-bearer[JWT Bearer]
+* xref:servlet/oauth2/client/authorization-grants.adoc#oauth2-client-token-exchange[Token Exchange]
 
 .Client Authentication support
-* https://datatracker.ietf.org/doc/html/rfc7523#section-2.2[JWT Bearer]
+* xref:servlet/oauth2/client/client-authentication.adoc#oauth2-client-jwt-bearer-authentication[JWT Bearer]
 
-.HTTP Client support
-* xref:servlet/oauth2/client/authorized-clients.adoc#oauth2-client-rest-client[`RestClient` integration] (for requesting protected resources)
-* xref:servlet/oauth2/client/authorized-clients.adoc#oauth2Client-webclient-servlet[`WebClient` integration for Servlet Environments] (for requesting protected resources)
+.HTTP Client support (for requesting protected resources)
+* xref:servlet/oauth2/client/authorized-clients.adoc#oauth2-client-rest-client[`RestClient` integration]
+* xref:servlet/oauth2/client/authorized-clients.adoc#oauth2-client-web-client[`WebClient` integration for Servlet Environments]
 
 The `HttpSecurity.oauth2Client()` DSL provides a number of configuration options for customizing the core components used by OAuth 2.0 Client.
 In addition, `HttpSecurity.oauth2Client().authorizationCodeGrant()` enables the customization of the Authorization Code grant.

+ 378 - 0
docs/modules/ROOT/partials/servlet/oauth2/client/rest-client-access-token-response-client.adoc

@@ -0,0 +1,378 @@
+To opt-in to using `{class-name}`, simply provide a bean as in the following example and it will be picked up by the default `OAuth2AuthorizedClientManager` automatically:
+
+[#oauth2-client-{section-id}-access-token-response-client-bean]
+.Access Token Response Configuration
+[tabs]
+======
+Java::
++
+[source,java,role="primary",subs="+attributes"]
+----
+@Bean
+public OAuth2AccessTokenResponseClient<{grant-request}> accessTokenResponseClient() {
+	return new {class-name}();
+}
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary",subs="+attributes"]
+----
+@Bean
+fun myAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<{grant-type}> {
+	return new {class-name}()
+}
+----
+======
+
+[NOTE]
+====
+The new implementation will be the default in Spring Security 7.
+====
+
+`{class-name}` is very flexible and provides several options for customizing the OAuth 2.0 Access Token request and response for the {grant-type} grant.
+Choose from the following use cases to learn more:
+
+* I want to <<oauth2-client-{section-id}-access-token-request-headers,customize headers of the Access Token request>>
+* I want to <<oauth2-client-{section-id}-access-token-request-parameters,customize parameters of the Access Token request>>
+* I want to <<oauth2-client-{section-id}-access-token-response,customize the instance of `RestClient` that is used>>
+* I want to <<oauth2-client-{section-id}-access-token-response-parameters,customize parameters of the Access Token response>>
+* I want to <<oauth2-client-{section-id}-access-token-response-errors,customize error handling of the Access Token response>>
+
+[#oauth2-client-{section-id}-access-token-request]
+== Customizing the Access Token Request
+
+`{class-name}` provides hooks for customizing HTTP headers and request parameters of the Token Request.
+
+[#oauth2-client-{section-id}-access-token-request-headers]
+=== Customizing Request Headers
+
+There are two options for customizing HTTP headers by providing a `Converter<{grant-request}, HttpHeaders>`:
+
+* Add additional headers by calling `addHeadersConverter(...)`
+* Fully customize headers by calling `setHeadersConverter(...)`
+
+You can include additional headers without affecting the default headers added to every request using `addHeadersConverter()`.
+The following example adds a `User-Agent` header to the request when the `registrationId` is `spring`:
+
+.Include Additional HTTP Headers
+[tabs]
+======
+Java::
++
+[source,java,role="primary",subs="+attributes"]
+----
+{class-name} accessTokenResponseClient =
+	new {class-name}();
+accessTokenResponseClient.addHeadersConverter((grantRequest) -> {
+	ClientRegistration clientRegistration = grantRequest.getClientRegistration();
+	HttpHeaders headers = new HttpHeaders();
+	if (clientRegistration.getRegistrationId().equals("spring")) {
+		headers.set(HttpHeaders.USER_AGENT, "...");
+	}
+	return headers;
+});
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary",subs="+attributes"]
+----
+val accessTokenResponseClient = {class-name}()
+accessTokenResponseClient.addHeadersConverter { grantRequest ->
+	val clientRegistration = grantRequest.getClientRegistration()
+	val headers = HttpHeaders()
+	if (clientRegistration.getRegistrationId() == "spring") {
+        headers[HttpHeaders.USER_AGENT] = "..."
+	}
+	headers
+}
+----
+======
+
+You can fully customize headers by re-using `DefaultOAuth2TokenRequestHeadersConverter` or providing a custom implementation using `setHeadersConverter()`.
+The following example re-uses `DefaultOAuth2TokenRequestHeadersConverter` and disables `encodeClientCredentials` so that HTTP Basic credentials are no longer encoded with `application/x-www-form-urlencoded`:
+
+.Customize HTTP Headers
+[tabs]
+======
+Java::
++
+[source,java,role="primary",subs="+attributes"]
+----
+DefaultOAuth2TokenRequestHeadersConverter headersConverter =
+	new DefaultOAuth2TokenRequestHeadersConverter();
+headersConverter.setEncodeClientCredentials(false);
+
+{class-name} accessTokenResponseClient =
+	new {class-name}();
+accessTokenResponseClient.setHeadersConverter(headersConverter);
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary",subs="+attributes"]
+----
+val headersConverter = DefaultOAuth2TokenRequestHeadersConverter()
+headersConverter.setEncodeClientCredentials(false)
+
+val accessTokenResponseClient = {class-name}()
+accessTokenResponseClient.setHeadersConverter(headersConverter)
+----
+======
+
+[#oauth2-client-{section-id}-access-token-request-parameters]
+=== Customizing Request Parameters
+
+There are two options for customizing request parameters by providing a `Converter<{grant-request}, MultiValueMap<String, String>>`:
+
+* Add additional parameters by calling `addParametersConverter(...)`
+* Override parameters by calling `setParametersConverter(...)`
+
+[NOTE]
+====
+Using `setParametersConverter()` does not fully customize parameters because it would require the user to provide all default parameters themselves.
+Default parameters are always provided, but can be fully customized or omitted by providing a `Consumer<MultiValueMap<String, String>>` to `setParametersCustomizer(...)`.
+====
+
+You can include additional parameters without affecting the default parameters added to every request using `addParametersConverter()`.
+The following example adds an `audience` parameter to the request when the `registrationId` is `keycloak`:
+
+.Include Additional Request Parameters
+[tabs]
+======
+Java::
++
+[source,java,role="primary",subs="+attributes"]
+----
+{class-name} accessTokenResponseClient =
+	new {class-name}();
+accessTokenResponseClient.addParametersConverter((grantRequest) -> {
+	ClientRegistration clientRegistration = grantRequest.getClientRegistration();
+	MultiValueMap<String, String> parameters = new LinkedMultiValueMap<String, String>();
+	if (clientRegistration.getRegistrationId().equals("keycloak")) {
+		parameters.set(OAuth2ParameterNames.AUDIENCE, "my-audience");
+	}
+	return parameters;
+});
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary",subs="+attributes"]
+----
+val accessTokenResponseClient = {class-name}()
+accessTokenResponseClient.addParametersConverter { grantRequest ->
+	val clientRegistration = grantRequest.getClientRegistration()
+	val parameters = LinkedMultiValueMap<String, String>()
+	if (clientRegistration.getRegistrationId() == "keycloak") {
+        parameters[OAuth2ParameterNames.AUDIENCE] = "my-audience"
+	}
+	parameters
+}
+----
+======
+
+You can override default parameters using `setParametersConverter()`.
+The following example overrides the `client_id` parameter when the `registrationId` is `okta`:
+
+.Override Request Parameters
+[tabs]
+======
+Java::
++
+[source,java,role="primary",subs="+attributes"]
+----
+{class-name} accessTokenResponseClient =
+	new {class-name}();
+accessTokenResponseClient.setParametersConverter((grantRequest) -> {
+	ClientRegistration clientRegistration = grantRequest.getClientRegistration();
+	LinkedMultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
+	if (clientRegistration.getRegistrationId().equals("okta")) {
+		parameters.set(OAuth2ParameterNames.CLIENT_ID, "my-client");
+	}
+	return parameters;
+});
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary",subs="+attributes"]
+----
+val parametersConverter = DefaultOAuth2TokenRequestParametersConverter<{grant-request}>()
+parametersConverter.setParametersCustomizer { parameters ->
+	if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
+		parameters.remove(OAuth2ParameterNames.CLIENT_ID)
+	}
+}
+
+val accessTokenResponseClient = {class-name}()
+accessTokenResponseClient.setParametersConverter { grantRequest ->
+    val clientRegistration = grantRequest.getClientRegistration()
+	val parameters = LinkedMultiValueMap<String, String>()
+	if (clientRegistration.getRegistrationId() == "okta") {
+        parameters[OAuth2ParameterNames.CLIENT_ID] = "my-client"
+	}
+	parameters
+}
+----
+======
+
+You can fully customize parameters (including omitting default parameters) using `setParametersCustomizer()`.
+The following example omits the `client_id` parameter when the `client_assertion` parameter is present in the request:
+
+.Omit Request Parameters
+[tabs]
+======
+Java::
++
+[source,java,role="primary",subs="+attributes"]
+----
+{class-name} accessTokenResponseClient =
+	new {class-name}();
+accessTokenResponseClient.setParametersCustomizer((parameters) -> {
+	if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
+		parameters.remove(OAuth2ParameterNames.CLIENT_ID);
+	}
+});
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary",subs="+attributes"]
+----
+val accessTokenResponseClient = {class-name}()
+accessTokenResponseClient.setParametersCustomizer { parameters ->
+	if (parameters.containsKey(OAuth2ParameterNames.CLIENT_ASSERTION)) {
+		parameters.remove(OAuth2ParameterNames.CLIENT_ID)
+	}
+}
+----
+======
+
+[#oauth2-client-{section-id}-access-token-response]
+== Customizing the Access Token Response
+
+You can customize the Token Response by providing a pre-configured `RestClient` to `setRestClient(...)`.
+The default `RestClient` is configured as follows:
+
+.Default `RestClient` Configuration
+[tabs]
+======
+Java::
++
+[source,java,role="primary",subs="+attributes"]
+----
+RestClient restClient = RestClient.builder()
+	.messageConverters((messageConverters) -> {
+		messageConverters.clear();
+		messageConverters.add(new FormHttpMessageConverter());
+		messageConverters.add(new OAuth2AccessTokenResponseHttpMessageConverter());
+	})
+	.defaultStatusHandler(new OAuth2ErrorResponseErrorHandler())
+	.build();
+
+{class-name} accessTokenResponseClient =
+	new {class-name}();
+accessTokenResponseClient.setRestClient(restClient);
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary",subs="+attributes"]
+----
+val restClient = RestClient.builder()
+	.messageConverters { messageConverters ->
+		messageConverters.clear()
+		messageConverters.add(FormHttpMessageConverter())
+		messageConverters.add(OAuth2AccessTokenResponseHttpMessageConverter())
+	}
+	.defaultStatusHandler(OAuth2ErrorResponseErrorHandler())
+	.build()
+
+val accessTokenResponseClient = {class-name}()
+accessTokenResponseClient.setRestClient(restClient)
+----
+======
+
+`OAuth2AccessTokenResponseHttpMessageConverter` is an `HttpMessageConverter` for an OAuth 2.0 Access Token Response.
+You can provide `setAccessTokenResponseConverter()` with a custom `Converter<Map<String, Object>, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`.
+
+`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, such as `400 Bad Request`.
+It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`.
+
+[TIP]
+====
+Spring MVC `FormHttpMessageConverter` is required, as it is used when sending the OAuth 2.0 Access Token Request.
+====
+
+[#oauth2-client-{section-id}-access-token-response-parameters]
+The following example provides a starting point for customizing the conversion of Token Response parameters to an `OAuth2AccessTokenResponse`:
+
+.Customize Access Token Response Converter
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+OAuth2AccessTokenResponseHttpMessageConverter accessTokenResponseMessageConverter =
+	new OAuth2AccessTokenResponseHttpMessageConverter();
+accessTokenResponseMessageConverter.setAccessTokenResponseConverter((parameters) -> {
+	// ...
+	return OAuth2AccessTokenResponse.withToken("custom-token")
+		// ...
+		.build();
+});
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+val accessTokenResponseMessageConverter = OAuth2AccessTokenResponseHttpMessageConverter()
+accessTokenResponseMessageConverter.setAccessTokenResponseConverter { parameters ->
+	// ...
+	return OAuth2AccessTokenResponse.withToken("custom-token")
+		// ...
+		.build()
+}
+----
+======
+
+[#oauth2-client-{section-id}-access-token-response-errors]
+The following example provides a starting point for customizing the conversion of Error parameters to an `OAuth2Error`:
+
+.Customize Access Token Error Handler
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+OAuth2ErrorHttpMessageConverter errorConverter =
+	new OAuth2ErrorHttpMessageConverter();
+errorConverter.setErrorConverter((parameters) -> {
+	// ...
+	return new OAuth2Error("custom-error", "custom description", "custom-uri");
+});
+
+OAuth2ErrorResponseErrorHandler errorHandler =
+	new OAuth2ErrorResponseErrorHandler();
+errorHandler.setErrorConverter(errorConverter);
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+val errorConverter = OAuth2ErrorHttpMessageConverter()
+errorConverter.setErrorConverter { parameters ->
+	// ...
+	return OAuth2Error("custom-error", "custom description", "custom-uri")
+}
+
+val errorHandler = OAuth2ErrorResponseErrorHandler()
+errorHandler.setErrorConverter(errorConverter)
+----
+======