diff --git a/docs/modules/ROOT/pages/servlet/oauth2/client/authorization-grants.adoc b/docs/modules/ROOT/pages/servlet/oauth2/client/authorization-grants.adoc index e7a5e1022a..5d248a1e70 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/client/authorization-grants.adoc +++ b/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 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. +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: -The `DefaultAuthorizationCodeTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request and/or post-handling of the Token Response. +* `DefaultAuthorizationCodeTokenResponseClient` (_default_) +* `RestClientAuthorizationCodeTokenResponseClient` +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 `DefaultAuthorizationCodeTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. -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). - -To customize only the parameters of the request, you can provide `OAuth2AuthorizationCodeGrantRequestEntityConverter.setParametersConverter()` with a custom `Converter>` to completely override the parameters sent with the request. This is often simpler than constructing a `RequestEntity` directly. - -[TIP] +[NOTE] ==== -If you prefer to only add additional parameters, you can provide `OAuth2AuthorizationCodeGrantRequestEntityConverter.addParametersConverter()` with a custom `Converter>` 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 <>) 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, 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>`. -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>` to completely override the parameters sent with the request. This is often simpler than constructing a `RequestEntity` directly. - -[TIP] +[NOTE] ==== -If you prefer to only add additional parameters, you can provide `OAuth2RefreshTokenGrantRequestEntityConverter.addParametersConverter()` with a custom `Converter>` which constructs an aggregate `Converter`. +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. ==== -[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: 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[] +:leveloffset: -1 -=== Customizing the Access Token Response +[[oauth2-client-refresh-token-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 `DefaultRefreshTokenTokenResponseClient.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, 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 <>) 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. +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: -The `DefaultClientCredentialsTokenResponseClient` is flexible, as it lets you customize the pre-processing of the Token Request or post-handling of the Token Response. +* `DefaultClientCredentialsTokenResponseClient` (_default_) +* `RestClientClientCredentialsTokenResponseClient` +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 `DefaultClientCredentialsTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. -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). - -To customize only the parameters of the request, you can provide `OAuth2ClientCredentialsGrantRequestEntityConverter.setParametersConverter()` with a custom `Converter>` to completely override the parameters sent with the request. This is often simpler than constructing a `RequestEntity` directly. - -[TIP] +[NOTE] ==== -If you prefer to only add additional parameters, you can provide `OAuth2ClientCredentialsGrantRequestEntityConverter.addParametersConverter()` with a custom `Converter>` 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, 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 <>) 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>`. @@ -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. +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: -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. +* `DefaultJwtBearerTokenResponseClient` (_default_) +* `RestClientJwtBearerTokenResponseClient` +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 `DefaultJwtBearerTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. -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>` 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>` 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 `DefaultJwtBearerTokenResponseClient.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] +[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, 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[] -`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`. +:leveloffset: -1 -Whether you customize `DefaultJwtBearerTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: +[[oauth2-client-jwt-bearer-authorized-client-provider-builder]] +=== Customize using the Builder + +Whether you customize `RestClientJwtBearerTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you can configure it using the `OAuth2AuthorizedClientProviderBuilder` (as an alternative to <>) as follows: [tabs] ====== @@ -1282,7 +1151,7 @@ OAuth2AuthorizedClientProvider authorizedClientProvider = .provider(jwtBearerAuthorizedClientProvider) .build(); -... +// ... authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); ---- @@ -1295,18 +1164,19 @@ Kotlin:: val jwtBearerTokenResponseClient: OAuth2AccessTokenResponseClient = ... 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`. -[[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. +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: -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. +* `DefaultTokenExchangeTokenResponseClient` (_default_) +* `RestClientTokenExchangeTokenResponseClient` +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 `DefaultTokenExchangeTokenResponseClient.setRequestEntityConverter()` with a custom `Converter>`. -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>` 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>` 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()); ----- - -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 `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, 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[] -`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`. +:leveloffset: -1 -Whether you customize `DefaultTokenExchangeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example: +[[oauth2-client-token-exchange-authorized-client-provider-builder]] +=== Customize using the Builder + +Whether you customize `RestClientTokenExchangeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you can configure it using the `OAuth2AuthorizedClientProviderBuilder` (as an alternative to <>) 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 - ... + // ... } } diff --git a/docs/modules/ROOT/pages/servlet/oauth2/client/authorized-clients.adoc b/docs/modules/ROOT/pages/servlet/oauth2/client/authorized-clients.adoc index 440cedf109..4ced96eeb3 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/client/authorized-clients.adoc +++ b/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. diff --git a/docs/modules/ROOT/pages/servlet/oauth2/client/client-authentication.adoc b/docs/modules/ROOT/pages/servlet/oauth2/client/client-authentication.adoc index edc3be5a37..85eb84b2e4 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/client/client-authentication.adoc +++ b/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. diff --git a/docs/modules/ROOT/pages/servlet/oauth2/client/index.adoc b/docs/modules/ROOT/pages/servlet/oauth2/client/index.adoc index 178c4b78d5..da239d1b57 100644 --- a/docs/modules/ROOT/pages/servlet/oauth2/client/index.adoc +++ b/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. diff --git a/docs/modules/ROOT/partials/servlet/oauth2/client/rest-client-access-token-response-client.adoc b/docs/modules/ROOT/partials/servlet/oauth2/client/rest-client-access-token-response-client.adoc new file mode 100644 index 0000000000..60377fa4a8 --- /dev/null +++ b/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 <> +* I want to <> +* I want to <> +* I want to <> +* I want to <> + +[#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>`: + +* 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>` 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 parameters = new LinkedMultiValueMap(); + 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() + 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 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() + 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, 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) +---- +======