1
0
mirror of synced 2026-05-22 21:33:16 +00:00

Remove Resource Owner Password Credentials grant

Closes gh-17446
This commit is contained in:
Joe Grandja
2025-07-02 17:12:47 -04:00
parent ee171a1c17
commit cfe38957d7
54 changed files with 103 additions and 3996 deletions
@@ -493,7 +493,7 @@ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
which is an implementation of a `ReactiveOAuth2AuthorizedClientProvider` for the Refresh Token grant.
====
The `OAuth2RefreshToken` may optionally be returned in the Access Token Response for the `authorization_code` and `password` grant types.
The `OAuth2RefreshToken` may optionally be returned in the Access Token Response for the `authorization_code` grant type.
If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2AuthorizedClient.getAccessToken()` is expired, it will automatically be refreshed by the `RefreshTokenReactiveOAuth2AuthorizedClientProvider`.
[[oauth2-client-client-credentials]]
@@ -698,264 +698,8 @@ class OAuth2ClientController {
If not provided, it will be obtained from the https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context] via the key `ServerWebExchange.class`.
====
[[oauth2-client-password]]
== [[oauth2Client-password-grant]]Resource Owner Password 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.3[Resource Owner Password Credentials] grant.
====
[[oauth2-client-password-access-token]]
=== Requesting an Access Token
[NOTE]
====
Please refer to the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/Response] protocol flow for the Resource Owner Password Credentials grant.
====
The default implementation of `ReactiveOAuth2AccessTokenResponseClient` for the Resource Owner Password Credentials grant is `WebClientReactivePasswordTokenResponseClient`, which uses a `WebClient` when requesting an access token at the Authorization Servers Token Endpoint.
[CAUTION]
====
The `WebClientReactivePasswordTokenResponseClient` class and support for the Resource Owner Password Credentials grant are deprecated.
This section will be removed in Spring Security 7.
====
:section-id: password
:grant-type: Password
:class-name: WebClientReactivePasswordTokenResponseClient
:grant-request: OAuth2PasswordGrantRequest
:leveloffset: +1
include::partial$reactive/oauth2/client/web-client-access-token-response-client.adoc[]
:leveloffset: -1
[[oauth2-client-password-authorized-client-provider-builder]]
=== Customize using the Builder
Whether you customize `WebClientReactivePasswordTokenResponseClient` or provide your own implementation of `ReactiveOAuth2AccessTokenResponseClient`, you can configure it using the `ReactiveOAuth2AuthorizedClientProviderBuilder` (as an alternative to <<oauth2-client-password-access-token-response-client-bean,publishing a bean>>) as follows:
.Access Token Response Configuration via Builder
[tabs]
======
Java::
+
[source,java,role="primary"]
----
// Customize
ReactiveOAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordTokenResponseClient = ...
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.password((configurer) -> configurer.accessTokenResponseClient(passwordTokenResponseClient))
.refreshToken()
.build();
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val passwordTokenResponseClient: ReactiveOAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> = ...
val authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.password { it.accessTokenResponseClient(passwordTokenResponseClient) }
.refreshToken()
.build()
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
----
======
[NOTE]
====
`ReactiveOAuth2AuthorizedClientProviderBuilder.builder().password()` configures a `PasswordReactiveOAuth2AuthorizedClientProvider`,
which is an implementation of a `ReactiveOAuth2AuthorizedClientProvider` for the Resource Owner Password Credentials grant.
====
[[oauth2-client-password-authorized-client-manager]]
=== Using the Access Token
Given the following Spring Boot properties for an OAuth 2.0 Client registration:
[source,yaml]
----
spring:
security:
oauth2:
client:
registration:
okta:
client-id: okta-client-id
client-secret: okta-client-secret
authorization-grant-type: password
scope: read, write
provider:
okta:
token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
----
...and the `ReactiveOAuth2AuthorizedClientManager` `@Bean`:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrationRepository,
ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build();
DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Assuming the `username` and `password` are supplied as `ServerHttpRequest` parameters,
// map the `ServerHttpRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());
return authorizedClientManager;
}
private Function<OAuth2AuthorizeRequest, Mono<Map<String, Object>>> contextAttributesMapper() {
return authorizeRequest -> {
Map<String, Object> contextAttributes = Collections.emptyMap();
ServerWebExchange exchange = authorizeRequest.getAttribute(ServerWebExchange.class.getName());
ServerHttpRequest request = exchange.getRequest();
String username = request.getQueryParams().getFirst(OAuth2ParameterNames.USERNAME);
String password = request.getQueryParams().getFirst(OAuth2ParameterNames.PASSWORD);
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
contextAttributes = new HashMap<>();
// `PasswordReactiveOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, username);
contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, password);
}
return Mono.just(contextAttributes);
};
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ReactiveClientRegistrationRepository,
authorizedClientRepository: ServerOAuth2AuthorizedClientRepository): ReactiveOAuth2AuthorizedClientManager {
val authorizedClientProvider: ReactiveOAuth2AuthorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build()
val authorizedClientManager = DefaultReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
// Assuming the `username` and `password` are supplied as `ServerHttpRequest` parameters,
// map the `ServerHttpRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper())
return authorizedClientManager
}
private fun contextAttributesMapper(): Function<OAuth2AuthorizeRequest, Mono<MutableMap<String, Any>>> {
return Function { authorizeRequest ->
var contextAttributes: MutableMap<String, Any> = mutableMapOf()
val exchange: ServerWebExchange = authorizeRequest.getAttribute(ServerWebExchange::class.java.name)!!
val request: ServerHttpRequest = exchange.request
val username: String? = request.queryParams.getFirst(OAuth2ParameterNames.USERNAME)
val password: String? = request.queryParams.getFirst(OAuth2ParameterNames.PASSWORD)
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
contextAttributes = hashMapOf()
// `PasswordReactiveOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes[OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME] = username!!
contextAttributes[OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME] = password!!
}
Mono.just(contextAttributes)
}
}
----
======
You may obtain the `OAuth2AccessToken` as follows:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Controller
public class OAuth2ClientController {
@Autowired
private ReactiveOAuth2AuthorizedClientManager authorizedClientManager;
@GetMapping("/")
public Mono<String> index(Authentication authentication, ServerWebExchange exchange) {
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal(authentication)
.attribute(ServerWebExchange.class.getName(), exchange)
.build();
return this.authorizedClientManager.authorize(authorizeRequest)
.map(OAuth2AuthorizedClient::getAccessToken)
// ...
.thenReturn("index");
}
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Controller
class OAuth2ClientController {
@Autowired
private lateinit var authorizedClientManager: ReactiveOAuth2AuthorizedClientManager
@GetMapping("/")
fun index(authentication: Authentication, exchange: ServerWebExchange): Mono<String> {
val authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal(authentication)
.attribute(ServerWebExchange::class.java.name, exchange)
.build()
return authorizedClientManager.authorize(authorizeRequest)
.map { it.accessToken }
// ...
.thenReturn("index")
}
}
----
======
[NOTE]
====
`ServerWebExchange` is an OPTIONAL attribute.
If not provided, it will be obtained from the https://projectreactor.io/docs/core/release/reference/#context[Reactor's Context] via the key `ServerWebExchange.class`.
====
[[oauth2-client-jwt-bearer]]
== [[oauth2Client-jwt-bearer-grant]]JWT Bearer
== JWT Bearer
[NOTE]
====
@@ -56,7 +56,6 @@ It directly uses an xref:reactive/oauth2/client/core.adoc#oauth2Client-authorize
* An `OAuth2AccessToken` will be requested if the client has not yet been authorized.
** `authorization_code` - triggers the Authorization Request redirect to initiate the flow
** `client_credentials` - the access token is obtained directly from the Token Endpoint
** `password` - the access token is obtained directly from the Token Endpoint
* If the `OAuth2AccessToken` is expired, it will be refreshed (or renewed) if a `ReactiveOAuth2AuthorizedClientProvider` is available to perform the authorization
The following code shows an example of how to configure `WebClient` with OAuth 2.0 Client support:
@@ -51,7 +51,7 @@ public final class ClientRegistration {
<4> `clientAuthenticationMethod`: The method used to authenticate the Client with the Provider.
The supported values are *client_secret_basic*, *client_secret_post*, *private_key_jwt*, *client_secret_jwt* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)].
<5> `authorizationGrantType`: The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types.
The supported values are `authorization_code`, `client_credentials`, `password`, as well as, extension grant type `urn:ietf:params:oauth:grant-type:jwt-bearer`.
The supported values are `authorization_code`, `client_credentials`, as well as, extension grant type `urn:ietf:params:oauth:grant-type:jwt-bearer`.
<6> `redirectUri`: The client's registered redirect URI that the _Authorization Server_ redirects the end-user's user-agent
to after the end-user has authenticated and authorized access to the client.
<7> `scopes`: The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile.
@@ -255,7 +255,7 @@ Implementations will typically implement an authorization grant type, eg. `autho
The default implementation of `ReactiveOAuth2AuthorizedClientManager` is `DefaultReactiveOAuth2AuthorizedClientManager`, which is associated with a `ReactiveOAuth2AuthorizedClientProvider` that may support multiple authorization grant types using a delegation-based composite.
The `ReactiveOAuth2AuthorizedClientProviderBuilder` may be used to configure and build the delegation-based composite.
The following code shows an example of how to configure and build a `ReactiveOAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token`, `client_credentials` and `password` authorization grant types:
The following code shows an example of how to configure and build a `ReactiveOAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token` and `client_credentials` authorization grant types:
[tabs]
======
@@ -273,7 +273,6 @@ public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager =
@@ -297,7 +296,6 @@ fun authorizedClientManager(
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build()
val authorizedClientManager = DefaultReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
@@ -312,7 +310,7 @@ In the case of a re-authorization failure, eg. a refresh token is no longer vali
The default behaviour may be customized via `setAuthorizationSuccessHandler(ReactiveOAuth2AuthorizationSuccessHandler)` and `setAuthorizationFailureHandler(ReactiveOAuth2AuthorizationFailureHandler)`.
The `DefaultReactiveOAuth2AuthorizedClientManager` is also associated with a `contextAttributesMapper` of type `Function<OAuth2AuthorizeRequest, Mono<Map<String, Object>>>`, which is responsible for mapping attribute(s) from the `OAuth2AuthorizeRequest` to a `Map` of attributes to be associated to the `OAuth2AuthorizationContext`.
This can be useful when you need to supply a `ReactiveOAuth2AuthorizedClientProvider` with required (supported) attribute(s), eg. the `PasswordReactiveOAuth2AuthorizedClientProvider` requires the resource owner's `username` and `password` to be available in `OAuth2AuthorizationContext.getAttributes()`.
This can be useful when you need to supply a `ReactiveOAuth2AuthorizedClientProvider` with required (supported) attribute(s).
The following code shows an example of the `contextAttributesMapper`:
@@ -329,7 +327,7 @@ public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.password()
.authorizationCode()
.refreshToken()
.build();
@@ -338,7 +336,7 @@ public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Assuming the `username` and `password` are supplied as `ServerHttpRequest` parameters,
// Assuming the attributes are supplied as `ServerHttpRequest` parameters,
// map the `ServerHttpRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());
@@ -350,14 +348,12 @@ private Function<OAuth2AuthorizeRequest, Mono<Map<String, Object>>> contextAttri
Map<String, Object> contextAttributes = Collections.emptyMap();
ServerWebExchange exchange = authorizeRequest.getAttribute(ServerWebExchange.class.getName());
ServerHttpRequest request = exchange.getRequest();
String username = request.getQueryParams().getFirst(OAuth2ParameterNames.USERNAME);
String password = request.getQueryParams().getFirst(OAuth2ParameterNames.PASSWORD);
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
String param1 = request.getQueryParams().getFirst("param1");
String param2 = request.getQueryParams().getFirst("param2");
if (StringUtils.hasText(param1) && StringUtils.hasText(param2)) {
contextAttributes = new HashMap<>();
// `PasswordReactiveOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, username);
contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, password);
contextAttributes.put("param1", param1);
contextAttributes.put("param2", param2);
}
return Mono.just(contextAttributes);
};
@@ -373,15 +369,15 @@ fun authorizedClientManager(
clientRegistrationRepository: ReactiveClientRegistrationRepository,
authorizedClientRepository: ServerOAuth2AuthorizedClientRepository): ReactiveOAuth2AuthorizedClientManager {
val authorizedClientProvider: ReactiveOAuth2AuthorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.password()
.authorizationCode()
.refreshToken()
.build()
val authorizedClientManager = DefaultReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
// Assuming the `username` and `password` are supplied as `ServerHttpRequest` parameters,
// map the `ServerHttpRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
// Assuming the attributes are supplied as `ServerHttpRequest` parameters,
// map the `ServerHttpRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper())
return authorizedClientManager
}
@@ -391,14 +387,12 @@ private fun contextAttributesMapper(): Function<OAuth2AuthorizeRequest, Mono<Mut
var contextAttributes: MutableMap<String, Any> = mutableMapOf()
val exchange: ServerWebExchange = authorizeRequest.getAttribute(ServerWebExchange::class.java.name)!!
val request: ServerHttpRequest = exchange.request
val username: String? = request.queryParams.getFirst(OAuth2ParameterNames.USERNAME)
val password: String? = request.queryParams.getFirst(OAuth2ParameterNames.PASSWORD)
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
val param1: String? = request.queryParams.getFirst("param1")
val param2: String? = request.queryParams.getFirst("param2")
if (StringUtils.hasText(param1) && StringUtils.hasText(param2)) {
contextAttributes = hashMapOf()
// `PasswordReactiveOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes[OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME] = username!!
contextAttributes[OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME] = password!!
contextAttributes["param1"] = param1!!
contextAttributes["param2"] = param2!!
}
Mono.just(contextAttributes)
}
@@ -10,7 +10,6 @@ At a high-level, the core features available are:
* xref:reactive/oauth2/client/authorization-grants.adoc#oauth2-client-authorization-code[Authorization Code]
* xref:reactive/oauth2/client/authorization-grants.adoc#oauth2-client-refresh-token[Refresh Token]
* xref:reactive/oauth2/client/authorization-grants.adoc#oauth2-client-client-credentials[Client Credentials]
* xref:reactive/oauth2/client/authorization-grants.adoc#oauth2-client-password[Resource Owner Password Credentials]
* xref:reactive/oauth2/client/authorization-grants.adoc#oauth2-client-jwt-bearer[JWT Bearer]
* xref:reactive/oauth2/client/authorization-grants.adoc#oauth2-client-token-exchange[Token Exchange]
@@ -81,7 +80,7 @@ class OAuth2ClientSecurityConfig {
The `ReactiveOAuth2AuthorizedClientManager` is responsible for managing the authorization (or re-authorization) of an OAuth 2.0 Client, in collaboration with one or more `ReactiveOAuth2AuthorizedClientProvider`(s).
The following code shows an example of how to register a `ReactiveOAuth2AuthorizedClientManager` `@Bean` and associate it with a `ReactiveOAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token`, `client_credentials` and `password` authorization grant types:
The following code shows an example of how to register a `ReactiveOAuth2AuthorizedClientManager` `@Bean` and associate it with a `ReactiveOAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token` and `client_credentials` authorization grant types:
[tabs]
======
@@ -99,7 +98,6 @@ public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager =
@@ -123,7 +121,6 @@ fun authorizedClientManager(
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build()
val authorizedClientManager = DefaultReactiveOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
@@ -953,7 +953,6 @@ public class SecurityConfig {
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.provider(new JwtBearerReactiveOAuth2AuthorizedClientProvider())
.build();
@@ -984,7 +983,6 @@ class SecurityConfig {
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.provider(JwtBearerReactiveOAuth2AuthorizedClientProvider())
.build()
@@ -1273,7 +1271,6 @@ Spring Security automatically resolves the following generic types of `ReactiveO
* `OAuth2AuthorizationCodeGrantRequest` (see `WebClientReactiveAuthorizationCodeTokenResponseClient`)
* `OAuth2RefreshTokenGrantRequest` (see `WebClientReactiveRefreshTokenTokenResponseClient`)
* `OAuth2ClientCredentialsGrantRequest` (see `WebClientReactiveClientCredentialsTokenResponseClient`)
* `OAuth2PasswordGrantRequest` (see `WebClientReactivePasswordTokenResponseClient`)
* `JwtBearerGrantRequest` (see `WebClientReactiveJwtBearerTokenResponseClient`)
* `TokenExchangeGrantRequest` (see `WebClientReactiveTokenExchangeTokenResponseClient`)
@@ -1334,15 +1331,6 @@ public class SecurityConfig {
return accessTokenResponseClient;
}
@Bean
public ReactiveOAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordAccessTokenResponseClient() {
WebClientReactivePasswordTokenResponseClient accessTokenResponseClient =
new WebClientReactivePasswordTokenResponseClient();
accessTokenResponseClient.setWebClient(webClient());
return accessTokenResponseClient;
}
@Bean
public ReactiveOAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() {
WebClientReactiveJwtBearerTokenResponseClient accessTokenResponseClient =
@@ -1400,14 +1388,6 @@ class SecurityConfig {
return accessTokenResponseClient
}
@Bean
fun passwordAccessTokenResponseClient(): ReactiveOAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> {
val accessTokenResponseClient = WebClientReactivePasswordTokenResponseClient()
accessTokenResponseClient.setWebClient(webClient())
return accessTokenResponseClient
}
@Bean
fun jwtBearerAccessTokenResponseClient(): ReactiveOAuth2AccessTokenResponseClient<JwtBearerGrantRequest> {
val accessTokenResponseClient = WebClientReactiveJwtBearerTokenResponseClient()
@@ -1477,10 +1457,6 @@ public class SecurityConfig {
new WebClientReactiveClientCredentialsTokenResponseClient();
clientCredentialsAccessTokenResponseClient.setWebClient(webClient());
WebClientReactivePasswordTokenResponseClient passwordAccessTokenResponseClient =
new WebClientReactivePasswordTokenResponseClient();
passwordAccessTokenResponseClient.setWebClient(webClient());
WebClientReactiveJwtBearerTokenResponseClient jwtBearerAccessTokenResponseClient =
new WebClientReactiveJwtBearerTokenResponseClient();
jwtBearerAccessTokenResponseClient.setWebClient(webClient());
@@ -1506,9 +1482,6 @@ public class SecurityConfig {
.clientCredentials((clientCredentials) -> clientCredentials
.accessTokenResponseClient(clientCredentialsAccessTokenResponseClient)
)
.password((password) -> password
.accessTokenResponseClient(passwordAccessTokenResponseClient)
)
.provider(jwtBearerAuthorizedClientProvider)
.provider(tokenExchangeAuthorizedClientProvider)
.build();
@@ -1557,9 +1530,6 @@ class SecurityConfig {
val clientCredentialsAccessTokenResponseClient = WebClientReactiveClientCredentialsTokenResponseClient()
clientCredentialsAccessTokenResponseClient.setWebClient(webClient())
val passwordAccessTokenResponseClient = WebClientReactivePasswordTokenResponseClient()
passwordAccessTokenResponseClient.setWebClient(webClient())
val jwtBearerAccessTokenResponseClient = WebClientReactiveJwtBearerTokenResponseClient()
jwtBearerAccessTokenResponseClient.setWebClient(webClient())
@@ -1580,9 +1550,6 @@ class SecurityConfig {
.clientCredentials { clientCredentials ->
clientCredentials.accessTokenResponseClient(clientCredentialsAccessTokenResponseClient)
}
.password { password ->
password.accessTokenResponseClient(passwordAccessTokenResponseClient)
}
.provider(jwtBearerAuthorizedClientProvider)
.provider(tokenExchangeAuthorizedClientProvider)
.build()
@@ -546,7 +546,7 @@ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
which is an implementation of an `OAuth2AuthorizedClientProvider` for the Refresh Token grant.
====
The `OAuth2RefreshToken` can optionally be returned in the Access Token Response for the `authorization_code` and `password` grant types.
The `OAuth2RefreshToken` can optionally be returned in the Access Token Response for the `authorization_code` grant type.
If the `OAuth2AuthorizedClient.getRefreshToken()` is available and the `OAuth2AuthorizedClient.getAccessToken()` is expired, it is automatically refreshed by the `RefreshTokenOAuth2AuthorizedClientProvider`.
[[oauth2-client-client-credentials]]
@@ -778,330 +778,8 @@ class OAuth2ClientController {
If not provided, they default to `ServletRequestAttributes` by using `RequestContextHolder.getRequestAttributes()`.
====
[[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]
====
See the https://tools.ietf.org/html/rfc6749#section-4.3.2[Access Token Request/Response] protocol flow for the Resource Owner Password Credentials grant.
====
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 Servers 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<?>>`.
The default implementation (`OAuth2PasswordGrantRequestEntityConverter`) builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.3.2[OAuth 2.0 Access Token Request].
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 `OAuth2PasswordGrantRequestEntityConverter.setParametersConverter()` with a custom `Converter<OAuth2PasswordGrantRequest, MultiValueMap<String, String>>` to completely override the parameters sent with the request. This is often simpler than constructing a `RequestEntity` directly.
[TIP]
====
If you prefer to only add additional parameters, you can provide `OAuth2PasswordGrantRequestEntityConverter.addParametersConverter()` with a custom `Converter<OAuth2PasswordGrantRequest, MultiValueMap<String, String>>` which constructs an aggregate `Converter`.
====
[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.
====
[[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`.
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.setTokenResponseConverter()` with a custom `Converter<Map<String, String>, OAuth2AccessTokenResponse>` that is used to convert the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`.
`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:
.Access Token Response Configuration via Builder
[tabs]
======
Java::
+
[source,java,role="primary"]
----
// Customize
OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordTokenResponseClient = ...
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.password((configurer) -> configurer.accessTokenResponseClient(passwordTokenResponseClient))
.refreshToken()
.build();
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
val passwordTokenResponseClient: OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> = ...
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.password { it.accessTokenResponseClient(passwordTokenResponseClient) }
.refreshToken()
.build()
// ...
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
----
======
[NOTE]
====
`OAuth2AuthorizedClientProviderBuilder.builder().password()` configures a `PasswordOAuth2AuthorizedClientProvider`,
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:
[source,yaml]
----
spring:
security:
oauth2:
client:
registration:
okta:
client-id: okta-client-id
client-secret: okta-client-secret
authorization-grant-type: password
scope: read, write
provider:
okta:
token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
----
Further consider the `OAuth2AuthorizedClientManager` `@Bean`:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());
return authorizedClientManager;
}
private Function<OAuth2AuthorizeRequest, Map<String, Object>> contextAttributesMapper() {
return authorizeRequest -> {
Map<String, Object> contextAttributes = Collections.emptyMap();
HttpServletRequest servletRequest = authorizeRequest.getAttribute(HttpServletRequest.class.getName());
String username = servletRequest.getParameter(OAuth2ParameterNames.USERNAME);
String password = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD);
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
contextAttributes = new HashMap<>();
// `PasswordOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, username);
contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, password);
}
return contextAttributes;
};
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Bean
fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.password()
.refreshToken()
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
// Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper())
return authorizedClientManager
}
private fun contextAttributesMapper(): Function<OAuth2AuthorizeRequest, MutableMap<String, Any>> {
return Function { authorizeRequest ->
var contextAttributes: MutableMap<String, Any> = mutableMapOf()
val servletRequest: HttpServletRequest = authorizeRequest.getAttribute(HttpServletRequest::class.java.name)
val username = servletRequest.getParameter(OAuth2ParameterNames.USERNAME)
val password = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD)
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
contextAttributes = hashMapOf()
// `PasswordOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes[OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME] = username
contextAttributes[OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME] = password
}
contextAttributes
}
}
----
======
Given the preceding properties and bean, you can obtain the `OAuth2AccessToken` as follows:
[tabs]
======
Java::
+
[source,java,role="primary"]
----
@Controller
public class OAuth2ClientController {
@Autowired
private OAuth2AuthorizedClientManager authorizedClientManager;
@GetMapping("/")
public String index(Authentication authentication,
HttpServletRequest servletRequest,
HttpServletResponse servletResponse) {
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal(authentication)
.attributes(attrs -> {
attrs.put(HttpServletRequest.class.getName(), servletRequest);
attrs.put(HttpServletResponse.class.getName(), servletResponse);
})
.build();
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
// ...
return "index";
}
}
----
Kotlin::
+
[source,kotlin,role="secondary"]
----
@Controller
class OAuth2ClientController {
@Autowired
private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
@GetMapping("/")
fun index(authentication: Authentication?,
servletRequest: HttpServletRequest,
servletResponse: HttpServletResponse): String {
val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal(authentication)
.attributes(Consumer {
it[HttpServletRequest::class.java.name] = servletRequest
it[HttpServletResponse::class.java.name] = servletResponse
})
.build()
val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
val accessToken: OAuth2AccessToken = authorizedClient.accessToken
// ...
return "index"
}
}
----
======
[NOTE]
====
`HttpServletRequest` and `HttpServletResponse` are both OPTIONAL attributes.
If not provided, they default to `ServletRequestAttributes` using `RequestContextHolder.getRequestAttributes()`.
====
[[oauth2-client-jwt-bearer]]
== [[oauth2Client-jwt-bearer-grant]]JWT Bearer
== JWT Bearer
[NOTE]
====
@@ -60,7 +60,6 @@ The interceptor directly uses an `OAuth2AuthorizedClientManager` and therefore i
* Performs an OAuth 2.0 Access Token request to obtain `OAuth2AccessToken` if the client has not yet been authorized
** `authorization_code`: Triggers the Authorization Request redirect to initiate the flow
** `client_credentials`: The access token is obtained directly from the Token Endpoint
** `password`: The access token is obtained directly from the Token Endpoint
** Additional grant types are supported by xref:servlet/oauth2/index.adoc#oauth2-client-enable-extension-grant-type[enabling extension grant types]
* If an existing `OAuth2AccessToken` is expired, it is refreshed (or renewed)
@@ -511,7 +510,6 @@ It directly uses an xref:servlet/oauth2/client/core.adoc#oauth2Client-authorized
* An `OAuth2AccessToken` is requested if the client has not yet been authorized.
** `authorization_code`: Triggers the Authorization Request redirect to initiate the flow.
** `client_credentials`: The access token is obtained directly from the Token Endpoint.
** `password`: The access token is obtained directly from the Token Endpoint.
* If the `OAuth2AccessToken` is expired, it is refreshed (or renewed) if an `OAuth2AuthorizedClientProvider` is available to perform the authorization
The following code shows an example of how to configure `WebClient` with OAuth 2.0 Client support:
@@ -52,7 +52,7 @@ public final class ClientRegistration {
<4> `clientAuthenticationMethod`: The method used to authenticate the Client with the Provider.
The supported values are *client_secret_basic*, *client_secret_post*, *private_key_jwt*, *client_secret_jwt* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)].
<5> `authorizationGrantType`: The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types.
The supported values are `authorization_code`, `client_credentials`, `password`, as well as, extension grant type `urn:ietf:params:oauth:grant-type:jwt-bearer`.
The supported values are `authorization_code`, `client_credentials`, as well as, extension grant type `urn:ietf:params:oauth:grant-type:jwt-bearer`.
<6> `redirectUri`: The client's registered redirect URI that the _Authorization Server_ redirects the end-user's user-agent
to after the end-user has authenticated and authorized access to the client.
<7> `scopes`: The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile.
@@ -268,7 +268,7 @@ Implementations typically implement an authorization grant type, such as `author
The default implementation of `OAuth2AuthorizedClientManager` is `DefaultOAuth2AuthorizedClientManager`, which is associated with an `OAuth2AuthorizedClientProvider` that may support multiple authorization grant types using a delegation-based composite.
You can use `OAuth2AuthorizedClientProviderBuilder` to configure and build the delegation-based composite.
The following code shows an example of how to configure and build an `OAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token`, `client_credentials`, and `password` authorization grant types:
The following code shows an example of how to configure and build an `OAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token` and `client_credentials` authorization grant types:
[tabs]
======
@@ -286,7 +286,6 @@ public OAuth2AuthorizedClientManager authorizedClientManager(
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
@@ -310,7 +309,6 @@ fun authorizedClientManager(
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
@@ -325,7 +323,7 @@ In the case of a re-authorization failure (for example, a refresh token is no lo
You can customize the default behavior through `setAuthorizationSuccessHandler(OAuth2AuthorizationSuccessHandler)` and `setAuthorizationFailureHandler(OAuth2AuthorizationFailureHandler)`.
The `DefaultOAuth2AuthorizedClientManager` is also associated with a `contextAttributesMapper` of type `Function<OAuth2AuthorizeRequest, Map<String, Object>>`, which is responsible for mapping attribute(s) from the `OAuth2AuthorizeRequest` to a `Map` of attributes to be associated to the `OAuth2AuthorizationContext`.
This can be useful when you need to supply an `OAuth2AuthorizedClientProvider` with required (supported) attribute(s), eg. the `PasswordOAuth2AuthorizedClientProvider` requires the resource owner's `username` and `password` to be available in `OAuth2AuthorizationContext.getAttributes()`.
This can be useful when you need to supply an `OAuth2AuthorizedClientProvider` with required (supported) attribute(s).
The following code shows an example of the `contextAttributesMapper`:
@@ -342,7 +340,7 @@ public OAuth2AuthorizedClientManager authorizedClientManager(
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.password()
.authorizationCode()
.refreshToken()
.build();
@@ -351,7 +349,7 @@ public OAuth2AuthorizedClientManager authorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
// Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
// Assuming the attributes are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper());
@@ -362,14 +360,12 @@ private Function<OAuth2AuthorizeRequest, Map<String, Object>> contextAttributesM
return authorizeRequest -> {
Map<String, Object> contextAttributes = Collections.emptyMap();
HttpServletRequest servletRequest = authorizeRequest.getAttribute(HttpServletRequest.class.getName());
String username = servletRequest.getParameter(OAuth2ParameterNames.USERNAME);
String password = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD);
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
String param1 = servletRequest.getParameter("param1");
String param2 = servletRequest.getParameter("param2");
if (StringUtils.hasText(param1) && StringUtils.hasText(param2)) {
contextAttributes = new HashMap<>();
// `PasswordOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, username);
contextAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, password);
contextAttributes.put("param1", param1);
contextAttributes.put("param2", param2);
}
return contextAttributes;
};
@@ -385,15 +381,15 @@ fun authorizedClientManager(
clientRegistrationRepository: ClientRegistrationRepository,
authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.password()
.authorizationCode()
.refreshToken()
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
// Assuming the `username` and `password` are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
// Assuming the attributes are supplied as `HttpServletRequest` parameters,
// map the `HttpServletRequest` parameters to `OAuth2AuthorizationContext.getAttributes()`
authorizedClientManager.setContextAttributesMapper(contextAttributesMapper())
return authorizedClientManager
}
@@ -402,14 +398,12 @@ private fun contextAttributesMapper(): Function<OAuth2AuthorizeRequest, MutableM
return Function { authorizeRequest ->
var contextAttributes: MutableMap<String, Any> = mutableMapOf()
val servletRequest: HttpServletRequest = authorizeRequest.getAttribute(HttpServletRequest::class.java.name)
val username: String = servletRequest.getParameter(OAuth2ParameterNames.USERNAME)
val password: String = servletRequest.getParameter(OAuth2ParameterNames.PASSWORD)
if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
val param1: String = servletRequest.getParameter("param1")
val param2: String = servletRequest.getParameter("param2")
if (StringUtils.hasText(param1) && StringUtils.hasText(param2)) {
contextAttributes = hashMapOf()
// `PasswordOAuth2AuthorizedClientProvider` requires both attributes
contextAttributes[OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME] = username
contextAttributes[OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME] = password
contextAttributes["param1"] = param1
contextAttributes["param2"] = param2
}
contextAttributes
}
@@ -10,7 +10,6 @@ At a high-level, the core features available are:
* 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]
@@ -104,7 +103,7 @@ The following code shows the complete configuration options available in the xre
The `OAuth2AuthorizedClientManager` is responsible for managing the authorization (or re-authorization) of an OAuth 2.0 Client, in collaboration with one or more `OAuth2AuthorizedClientProvider`(s).
The following code shows an example of how to register an `OAuth2AuthorizedClientManager` `@Bean` and associate it with an `OAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token`, `client_credentials`, and `password` authorization grant types:
The following code shows an example of how to register an `OAuth2AuthorizedClientManager` `@Bean` and associate it with an `OAuth2AuthorizedClientProvider` composite that provides support for the `authorization_code`, `refresh_token` and `client_credentials` authorization grant types:
[tabs]
======
@@ -122,7 +121,6 @@ public OAuth2AuthorizedClientManager authorizedClientManager(
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
@@ -146,7 +144,6 @@ fun authorizedClientManager(
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build()
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository)
@@ -1367,7 +1367,6 @@ public class SecurityConfig {
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.provider(new JwtBearerOAuth2AuthorizedClientProvider())
.build();
@@ -1398,7 +1397,6 @@ class SecurityConfig {
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.provider(JwtBearerOAuth2AuthorizedClientProvider())
.build()
@@ -1699,7 +1697,6 @@ Spring Security automatically resolves the following generic types of `OAuth2Acc
* `OAuth2AuthorizationCodeGrantRequest` (see `DefaultAuthorizationCodeTokenResponseClient`)
* `OAuth2RefreshTokenGrantRequest` (see `DefaultRefreshTokenTokenResponseClient`)
* `OAuth2ClientCredentialsGrantRequest` (see `DefaultClientCredentialsTokenResponseClient`)
* `OAuth2PasswordGrantRequest` (see `DefaultPasswordTokenResponseClient`)
* `JwtBearerGrantRequest` (see `DefaultJwtBearerTokenResponseClient`)
* `TokenExchangeGrantRequest` (see `DefaultTokenExchangeTokenResponseClient`)
@@ -1760,15 +1757,6 @@ public class SecurityConfig {
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordAccessTokenResponseClient() {
DefaultPasswordTokenResponseClient accessTokenResponseClient =
new DefaultPasswordTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() {
DefaultJwtBearerTokenResponseClient accessTokenResponseClient =
@@ -1826,14 +1814,6 @@ class SecurityConfig {
return accessTokenResponseClient
}
@Bean
fun passwordAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> {
val accessTokenResponseClient = DefaultPasswordTokenResponseClient()
accessTokenResponseClient.setRestOperations(restTemplate())
return accessTokenResponseClient
}
@Bean
fun jwtBearerAccessTokenResponseClient(): OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> {
val accessTokenResponseClient = DefaultJwtBearerTokenResponseClient()
@@ -1917,10 +1897,6 @@ public class SecurityConfig {
new DefaultClientCredentialsTokenResponseClient();
clientCredentialsAccessTokenResponseClient.setRestOperations(restTemplate());
DefaultPasswordTokenResponseClient passwordAccessTokenResponseClient =
new DefaultPasswordTokenResponseClient();
passwordAccessTokenResponseClient.setRestOperations(restTemplate());
DefaultJwtBearerTokenResponseClient jwtBearerAccessTokenResponseClient =
new DefaultJwtBearerTokenResponseClient();
jwtBearerAccessTokenResponseClient.setRestOperations(restTemplate());
@@ -1946,9 +1922,6 @@ public class SecurityConfig {
.clientCredentials((clientCredentials) -> clientCredentials
.accessTokenResponseClient(clientCredentialsAccessTokenResponseClient)
)
.password((password) -> password
.accessTokenResponseClient(passwordAccessTokenResponseClient)
)
.provider(jwtBearerAuthorizedClientProvider)
.provider(tokenExchangeAuthorizedClientProvider)
.build();
@@ -2012,9 +1985,6 @@ class SecurityConfig {
val clientCredentialsAccessTokenResponseClient = DefaultClientCredentialsTokenResponseClient()
clientCredentialsAccessTokenResponseClient.setRestOperations(restTemplate())
val passwordAccessTokenResponseClient = DefaultPasswordTokenResponseClient()
passwordAccessTokenResponseClient.setRestOperations(restTemplate())
val jwtBearerAccessTokenResponseClient = DefaultJwtBearerTokenResponseClient()
jwtBearerAccessTokenResponseClient.setRestOperations(restTemplate())
@@ -2035,9 +2005,6 @@ class SecurityConfig {
.clientCredentials { clientCredentials ->
clientCredentials.accessTokenResponseClient(clientCredentialsAccessTokenResponseClient)
}
.password { password ->
password.accessTokenResponseClient(passwordAccessTokenResponseClient)
}
.provider(jwtBearerAuthorizedClientProvider)
.provider(tokenExchangeAuthorizedClientProvider)
.build()