Add overview documentation for OAuth2

This commit adds an overview to the landing page for OAuth2 with:
* OAuth2 Resource Server
* OAuth2 Client

At this level, OAuth2 Login is combined into the overview for Client
to make it clear that it is part of the oauth2-client module.

Content is broken down into use cases similar to other docs pages
that have been updated recently. This content will be revisited
as additional updates are made to OAuth2 docs, and some use cases
may be moved or even added as needed. This commit only adds a few
initial use cases to get the OAuth2 docs update process started.

Closes gh-13784
This commit is contained in:
Steve Riesenberg 2023-08-10 16:47:51 -05:00
parent 92256f0522
commit 1f8c94aee8
No known key found for this signature in database
GPG Key ID: 5F311AB48A55D521
1 changed files with 961 additions and 3 deletions

View File

@ -1,7 +1,965 @@
= OAuth2
:page-section-summary-toc: 1
Spring Security provides comprehensive OAuth 2 support.
This section discusses how to integrate OAuth 2 into your servlet based application.
Spring Security provides comprehensive OAuth 2.0 support.
This section discusses how to integrate OAuth 2.0 into your servlet based application.
[[oauth2-overview]]
== Overview
Spring Security's OAuth 2.0 support consists of two primary feature sets:
* <<oauth2-resource-server>>
* <<oauth2-client>>
[NOTE]
====
<<oauth2-client-log-users-in,OAuth2 Login>> is a very powerful OAuth2 Client feature that deserves its own section in the reference documentation.
However, it does not exist as a standalone feature and requires OAuth2 Client in order to function.
====
These feature sets cover the _resource server_ and _client_ roles defined in the https://tools.ietf.org/html/rfc6749#section-1.1[OAuth 2.0 Authorization Framework], while the _authorization server_ role is covered by https://docs.spring.io/spring-authorization-server/reference/index.html[Spring Authorization Server], which is a separate project built on xref:index.adoc[Spring Security].
The _resource server_ and _client_ roles in OAuth2 are typically represented by one or more server-side applications.
Additionally, the _authorization server_ role can be represented by one or more third parties (as is the case when centralizing identity management and/or authentication within an organization) *-or-* it can be represented by an application (as is the case with Spring Authorization Server).
For example, a typical OAuth2-based microservices architecture might consist of a single user-facing client application, several backend resource servers providing REST APIs and a third party authorization server for managing users and authentication concerns.
It is also common to have a single application representing only one of these roles with the need to integrate with one or more third parties that are providing the other roles.
Spring Security handles these scenarios and more.
The following sections cover the roles provided by Spring Security and contain examples for common scenarios.
[[oauth2-resource-server]]
== OAuth2 Resource Server
[NOTE]
====
This section contains a summary of OAuth2 Resource Server features with examples.
See xref:servlet/oauth2/resource-server/index.adoc[OAuth 2.0 Resource Server] for complete reference documentation.
====
To get started, add the `spring-security-oauth2-resource-server` dependency to your project.
When using Spring Boot, add the following starter:
.OAuth2 Client with Spring Boot
[tabs]
======
Gradle::
+
[source,gradle,role="primary"]
----
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
----
Maven::
+
[source,maven,role="secondary"]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
----
======
[TIP]
====
See xref:getting-spring-security.adoc[] for additional options when not using Spring Boot.
====
Consider the following use cases for OAuth2 Resource Server:
* <<oauth2-resource-server-access-token,I want to protect access to the API using OAuth2>> (authorization server provides JWT or opaque access token)
* <<oauth2-resource-server-custom-jwt,I want to protect access to the API using a JWT>> (custom token)
[[oauth2-resource-server-access-token]]
=== Protect Access with an OAuth2 Access Token
It is very common to protect access to an API using OAuth2 access tokens.
In most cases, Spring Security requires only minimal configuration to secure an application with OAuth2.
There are two types of `Bearer` tokens supported by Spring Security which each use a different component for validation:
* <<oauth2-resource-server-access-token-jwt,JWT support>> uses a `JwtDecoder` bean to validate signatures and decode tokens
* <<oauth2-resource-server-access-token-opaque,Opaque token support>> uses an `OpaqueTokenIntrospector` bean to introspect tokens
[[oauth2-resource-server-access-token-jwt]]
==== JWT Support
The following example configures a `JwtDecoder` bean using Spring Boot configuration properties:
[source,yaml]
----
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://my-auth-server.com
----
When using Spring Boot, this is all that is required.
The default arrangement provided by Spring Boot is equivalent to the following:
[source,java]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.oauth2ResourceServer((oauth2) -> oauth2
.jwt(Customizer.withDefaults())
);
return http.build();
}
@Bean
public JwtDecoder jwtDecoder() {
return JwtDecoders.fromIssuerLocation("https://my-auth-server.com");
}
}
----
[[oauth2-resource-server-access-token-opaque]]
==== Opaque Token Support
The following example configures an `OpaqueTokenIntrospector` bean using Spring Boot configuration properties:
[source,yaml]
----
spring:
security:
oauth2:
resourceserver:
opaquetoken:
introspection-uri: https://my-auth-server.com/oauth2/introspect
client-id: my-client-id
client-secret: my-client-secret
----
When using Spring Boot, this is all that is required.
The default arrangement provided by Spring Boot is equivalent to the following:
[source,java]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.oauth2ResourceServer((oauth2) -> oauth2
.opaqueToken(Customizer.withDefaults())
);
return http.build();
}
@Bean
public OpaqueTokenIntrospector opaqueTokenIntrospector() {
return new SpringOpaqueTokenIntrospector(
"https://my-auth-server.com/oauth2/introspect", "my-client-id", "my-client-secret");
}
}
----
[[oauth2-resource-server-custom-jwt]]
=== Protect Access with a custom JWT
It is a fairly common goal to protect access to an API using JWTs, particularly when the frontend is developed as a single-page application.
The OAuth2 Resource Server support in Spring Security can be used for any type of `Bearer` token, including a custom JWT.
All that is required to protect an API using JWTs is a `JwtDecoder` bean, which is used to validate signatures and decode tokens.
Spring Security will automatically use the provided bean to configure protection within the `SecurityFilterChain`.
The following example configures a `JwtDecoder` bean using Spring Boot configuration properties:
[source,yaml]
----
spring:
security:
oauth2:
resourceserver:
jwt:
public-key-location: classpath:my-public-key.pub
----
[NOTE]
====
You can provide the public key as a classpath resource (called `my-public-key.pub` in this example).
====
When using Spring Boot, this is all that is required.
The default arrangement provided by Spring Boot is equivalent to the following:
[source,java]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.oauth2ResourceServer((oauth2) -> oauth2
.jwt(Customizer.withDefaults())
);
return http.build();
}
@Bean
public JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(publicKey()).build();
}
private RSAPublicKey publicKey() {
// ...
}
}
----
[NOTE]
====
Spring Security does not provide an endpoint for minting tokens.
However, Spring Security does provides the `JwtEncoder` interface along with one implementation, which is `NimbusJwtEncoder`.
====
[[oauth2-client]]
== OAuth2 Client
[NOTE]
====
This section contains a summary of OAuth2 Client features with examples.
See xref:servlet/oauth2/client/index.adoc[OAuth 2.0 Client] and xref:servlet/oauth2/login/index.adoc[OAuth 2.0 Login] for complete reference documentation.
====
To get started, add the `spring-security-oauth2-client` dependency to your project.
When using Spring Boot, add the following starter:
.OAuth2 Client with Spring Boot
[tabs]
======
Gradle::
+
[source,gradle,role="primary"]
----
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
----
Maven::
+
[source,maven,role="secondary"]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
----
======
[TIP]
====
See xref:getting-spring-security.adoc[] for additional options when not using Spring Boot.
====
Consider the following use cases for OAuth2 Client:
* <<oauth2-client-log-users-in,I want to log users in using OAuth 2.0 or OpenID Connect 1.0>>
* <<oauth2-client-access-protected-resources,I want to obtain an access token for users in order to access a third-party API>>
* <<oauth2-client-access-protected-resources-current-user,I want to do both>> (log users in _and_ access a third-party API)
* <<oauth2-client-enable-extension-grant-type,I want to enable an extension grant type>>
* <<oauth2-client-customize-existing-grant-type,I want to customize an existing grant type>>
* <<oauth2-client-customize-request-parameters,I want to customize token request parameters>>
* <<oauth2-client-customize-rest-operations,I want to customize the `RestOperations` used by OAuth2 Client components>>
[[oauth2-client-log-users-in]]
=== Log Users In with OAuth2
It is very common to require users to log in via OAuth2.
https://openid.net/specs/openid-connect-core-1_0.html[OpenID Connect 1.0] provides a special token called the `id_token` which is designed to provide an OAuth2 Client with the ability to perform user identity verification and log users in.
In certain cases, OAuth2 can be used directly to log users in (as is the case with popular social login providers that do not implement OpenID Connect such as GitHub and Facebook).
The following example configures the application to act as an OAuth2 Client capable of logging users in with OAuth2 or OpenID Connect.
[source,java]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.oauth2Login(Customizer.withDefaults());
return http.build();
}
}
----
In addition to the above configuration, the application requires at least one `ClientRegistration` to be configured through the use of a `ClientRegistrationRepository` bean.
The following example configures an `InMemoryClientRegistrationRepository` bean using Spring Boot configuration properties:
[source,yaml]
----
spring:
security:
oauth2:
client:
registration:
my-oidc-client:
provider: my-oidc-provider
client-id: my-client-id
client-secret: my-client-secret
authorization-grant-type: authorization_code
scope: openid,profile
provider:
my-oidc-provider:
issuer-uri: https://my-oidc-provider.com
----
With the above configuration, the application now supports two additional endpoints:
1. The login endpoint (e.g. `/oauth2/authorization/my-oidc-client`) is used to initiate login and perform a redirect to the third party authorization server.
2. The redirection endpoint (e.g. `/login/oauth2/code/my-oidc-client`) is used by the authorization server to redirect back to the client application, and will contain a `code` parameter used to obtain an `id_token` and/or `access_token` via the access token request.
[NOTE]
====
The presence of the `openid` scope in the above configuration indicates that OpenID Connect 1.0 should be used.
This instructs Spring Security to use OIDC-specific components (such as `OidcUserService`) during request processing.
Without this scope, Spring Security will use OAuth2-specific components (such as `OAuth2UserService`) instead.
====
[[oauth2-client-access-protected-resources]]
=== Access Protected Resources
Making requests to a third party API that is protected by OAuth2 is a core use case of OAuth2 Client.
This is accomplished by authorizing a client (represented by the `OAuth2AuthorizedClient` class in Spring Security) and accessing protected resources by placing a `Bearer` token in the `Authorization` header of an outbound request.
The following example configures the application to act as an OAuth2 Client capable of requesting protected resources from a third party API.
[source,java]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.oauth2Client(Customizer.withDefaults());
return http.build();
}
}
----
[NOTE]
====
The above example does not provide a way to log users in.
You can use any other login mechanism (such as `formLogin()`).
See the <<oauth2-client-access-protected-resources-current-user,next section>> for an example combining `oauth2Client()` with `oauth2Login()`.
====
In addition to the above configuration, the application requires at least one `ClientRegistration` to be configured through the use of a `ClientRegistrationRepository` bean.
The following example configures an `InMemoryClientRegistrationRepository` bean using Spring Boot configuration properties:
[source,yaml]
----
spring:
security:
oauth2:
client:
registration:
my-oauth2-client:
provider: my-auth-server
client-id: my-client-id
client-secret: my-client-secret
authorization-grant-type: authorization_code
scope: message.read,message.write
provider:
my-auth-server:
issuer-uri: https://my-auth-server.com
----
In addition to configuring Spring Security to support OAuth2 Client features, you will also need to decide how you will be accessing protected resources and configure your application accordingly.
Spring Security provides implementations of `OAuth2AuthorizedClientManager` for obtaining access tokens that can be used to access protected resources.
[TIP]
====
Spring Security registers a default `OAuth2AuthorizedClientManager` bean for you when one does not exist.
====
The following example uses the default `OAuth2AuthorizedClientManager` to configure a `WebClient` capable of accessing protected resources by placing `Bearer` tokens in the `Authorization` header of each request:
[source,java]
----
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction filter =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
return WebClient.builder()
.apply(filter.oauth2Configuration())
.build();
}
}
----
This configured `WebClient` can be used as in the following example:
[[oauth2-client-accessing-protected-resources-example]]
[source,java]
----
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
@RestController
public class MessagesController {
private final WebClient webClient;
public MessagesController(WebClient webClient) {
this.webClient = webClient;
}
@GetMapping("/messages")
public ResponseEntity<List<Message>> messages() {
return this.webClient.get()
.uri("http://localhost:8090/messages")
.attributes(clientRegistrationId("my-oauth2-client"))
.retrieve()
.toEntityList(Message.class)
.block();
}
}
----
[[oauth2-client-access-protected-resources-current-user]]
=== Access Protected Resources for the Current User
When a user is logged in via OAuth2 or OpenID Connect, the authorization server may provide an access token that can be used directly to access protected resources.
This is convenient because it only requires a single `ClientRegistration` to be configured for both use cases simultaneously.
[NOTE]
====
This section combines <<oauth2-client-log-users-in>> and <<oauth2-client-access-protected-resources>> into a single configuration.
Other advanced scenarios exist, such as configuring one `ClientRegistration` for login and another for accessing protected resources.
All such scenarios would use the same basic configuration.
====
The following example configures the application to act as an OAuth2 Client capable of logging the user in _and_ requesting protected resources from a third party API.
[source,java]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.oauth2Login(Customizer.withDefaults())
.oauth2Client(Customizer.withDefaults());
return http.build();
}
}
----
In addition to the above configuration, the application requires at least one `ClientRegistration` to be configured through the use of a `ClientRegistrationRepository` bean.
The following example configures an `InMemoryClientRegistrationRepository` bean using Spring Boot configuration properties:
[source,yaml]
----
spring:
security:
oauth2:
client:
registration:
my-combined-client:
provider: my-auth-server
client-id: my-client-id
client-secret: my-client-secret
authorization-grant-type: authorization_code
scope: openid,profile,message.read,message.write
provider:
my-auth-server:
issuer-uri: https://my-auth-server.com
----
[NOTE]
====
The main difference between the previous examples (<<oauth2-client-log-users-in>>, <<oauth2-client-access-protected-resources>>) and this one is what is configured via the `scope` property, which combines the standard scopes `openid` and `profile` with the custom scopes `message.read` and `message.write`.
====
In addition to configuring Spring Security to support OAuth2 Client features, you will also need to decide how you will be accessing protected resources and configure your application accordingly.
Spring Security provides implementations of `OAuth2AuthorizedClientManager` for obtaining access tokens that can be used to access protected resources.
[TIP]
====
Spring Security registers a default `OAuth2AuthorizedClientManager` bean for you when one does not exist.
====
The following example uses the default `OAuth2AuthorizedClientManager` to configure a `WebClient` capable of accessing protected resources by placing `Bearer` tokens in the `Authorization` header of each request.
[source,java]
----
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction filter =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
return WebClient.builder()
.apply(filter.oauth2Configuration())
.build();
}
}
----
This configured `WebClient` can be used as in the following example:
[[oauth2-client-accessing-protected-resources-current-user-example]]
[source,java]
----
@RestController
public class MessagesController {
private final WebClient webClient;
public MessagesController(WebClient webClient) {
this.webClient = webClient;
}
@GetMapping("/messages")
public ResponseEntity<List<Message>> messages() {
return this.webClient.get()
.uri("http://localhost:8090/messages")
.retrieve()
.toEntityList(Message.class)
.block();
}
}
----
[NOTE]
====
Unlike the <<oauth2-client-accessing-protected-resources-example,previous example>>, notice that we do not need to tell Spring Security about the `clientRegistrationId` we'd like to use.
This is because it can be derived from the currently logged in user.
====
[[oauth2-client-enable-extension-grant-type]]
=== Enable an Extension Grant Type
A common use case involves enabling and/or configuring an extension grant type.
For example, Spring Security provides support for the `jwt-bearer` grant type, but does not enable it by default because it is not part of the core OAuth 2.0 specification.
With Spring Security 6.2 and later, we can simply publish a bean for one or more `OAuth2AuthorizedClientProvider` and they will be picked up automatically.
The following example simply enables the `jwt-bearer` grant type:
[source,java]
----
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AuthorizedClientProvider jwtBearer() {
return new JwtBearerOAuth2AuthorizedClientProvider();
}
}
----
A default `OAuth2AuthorizedClientManager` will be published automatically by Spring Security when one is not already provided.
[TIP]
====
Any custom `OAuth2AuthorizedClientProvider` bean will also be picked up and applied to the provided `OAuth2AuthorizedClientManager` after the default grant types.
====
In order to achieve the above configuration prior to Spring Security 6.2, we had to publish this bean ourselves and ensure we re-enabled default grant types as well.
To understand what is being configured behind the scenes, here's what the configuration might have looked like:
[source,java]
----
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.provider(new JwtBearerOAuth2AuthorizedClientProvider())
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}
----
[[oauth2-client-customize-existing-grant-type]]
=== Customize an Existing Grant Type
The ability to <<oauth2-client-enable-extension-grant-type,enable extension grant types>> by publishing a bean also provides the opportunity for customizing an existing grant type without the need to re-define the defaults.
For example, if we want to customize the clock skew of the `OAuth2AuthorizedClientProvider` for the `client_credentials` grant, we can simply publish a bean like so:
[source,java]
----
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AuthorizedClientProvider clientCredentials() {
ClientCredentialsOAuth2AuthorizedClientProvider authorizedClientProvider =
new ClientCredentialsOAuth2AuthorizedClientProvider();
authorizedClientProvider.setClockSkew(Duration.ofMinutes(5));
return authorizedClientProvider;
}
}
----
[[oauth2-client-customize-request-parameters]]
=== Customize Token Request Parameters
The need to customize request parameters when obtaining an access token is fairly common.
For example, let's say we want to add a custom `audience` parameter to the token request because the provider requires this parameter for the `authorization_code` grant.
With Spring Security 6.2 and later, we can simply publish a bean of type `OAuth2AccessTokenResponseClient` with the generic type `OAuth2AuthorizationCodeGrantRequest` and it will be used by Spring Security to configure OAuth2 Client components.
The following example customizes token request parameters for the `authorization_code` grant without the DSL:
[source,java]
----
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() {
OAuth2AuthorizationCodeGrantRequestEntityConverter requestEntityConverter =
new OAuth2AuthorizationCodeGrantRequestEntityConverter();
requestEntityConverter.addParametersConverter(parametersConverter());
DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new DefaultAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
return accessTokenResponseClient;
}
private static Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> parametersConverter() {
// ...
}
}
----
[TIP]
====
Notice that we don't need to customize the `SecurityFilterChain` bean in this case, and can stick with the defaults.
If using Spring Boot with no additional customizations, we can actually omit the `SecurityFilterChain` bean entirely.
====
Prior to Spring Security 6.2, we had to ensure that this customization was applied for both OAuth2 Login (if we are using this feature) and OAuth2 Client components using the Spring Security DSL.
To understand what is being configured behind the scenes, here's what the configuration might have looked like:
[source,java]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationCodeGrantRequestEntityConverter requestEntityConverter =
new OAuth2AuthorizationCodeGrantRequestEntityConverter();
requestEntityConverter.addParametersConverter(parametersConverter());
DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new DefaultAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.oauth2Login((oauth2Login) -> oauth2Login
.tokenEndpoint((tokenEndpoint) -> tokenEndpoint
.accessTokenResponseClient(accessTokenResponseClient)
)
)
.oauth2Client((oauth2Client) -> oauth2Client
.authorizationCodeGrant((authorizationCode) -> authorizationCode
.accessTokenResponseClient(accessTokenResponseClient)
)
);
return http.build();
}
private static Converter<OAuth2AuthorizationCodeGrantRequest, MultiValueMap<String, String>> parametersConverter() {
return (grantRequest) -> {
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
parameters.set("audience", "xyz_value");
return parameters;
};
}
}
----
In either case, for other grant types we can publish additional `OAuth2AccessTokenResponseClient` beans to override the defaults.
For example, to customize token requests for the `client_credentials` grant we can publish the following bean:
[source,java]
----
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
OAuth2ClientCredentialsGrantRequestEntityConverter requestEntityConverter =
new OAuth2ClientCredentialsGrantRequestEntityConverter();
requestEntityConverter.addParametersConverter(parametersConverter());
DefaultClientCredentialsTokenResponseClient accessTokenResponseClient =
new DefaultClientCredentialsTokenResponseClient();
accessTokenResponseClient.setRequestEntityConverter(requestEntityConverter);
return accessTokenResponseClient;
}
private static Converter<OAuth2ClientCredentialsGrantRequest, MultiValueMap<String, String>> parametersConverter() {
// ...
}
}
----
Spring Security automatically resolves the following generic types of `OAuth2AccessTokenResponseClient` beans:
* `OAuth2AuthorizationCodeGrantRequest` (see `DefaultAuthorizationCodeTokenResponseClient`)
* `OAuth2RefreshTokenGrantRequest` (see `DefaultRefreshTokenTokenResponseClient`)
* `OAuth2ClientCredentialsGrantRequest` (see `DefaultClientCredentialsTokenResponseClient`)
* `OAuth2PasswordGrantRequest` (see `DefaultPasswordTokenResponseClient`)
* `JwtBearerGrantRequest` (see `DefaultJwtBearerTokenResponseClient`)
[TIP]
====
Publishing a bean of type `OAuth2AccessTokenResponseClient<JwtBearerGrantRequest>` will automatically enable the `jwt-bearer` grant type without the need to configure it separately.
====
[[oauth2-client-customize-rest-operations]]
=== Customize the `RestOperations` used by OAuth2 Client Components
Another common use case is the need to customize the `RestOperations` used when obtaining an access token.
We might need to do this to customize processing of the response (via a custom `HttpMessageConverter`) or to apply proxy settings for a corporate network (via a customized `ClientHttpRequestFactory`).
With Spring Security 6.2 and later, we can simply publish beans of type `OAuth2AccessTokenResponseClient` and Spring Security will configure and publish an `OAuth2AuthorizedClientManager` bean for us.
The following example customizes the `RestOperations` for all of the supported grant types:
[source,java]
----
@Configuration
public class SecurityConfig {
@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeAccessTokenResponseClient() {
DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new DefaultAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2RefreshTokenGrantRequest> refreshTokenAccessTokenResponseClient() {
DefaultRefreshTokenTokenResponseClient accessTokenResponseClient =
new DefaultRefreshTokenTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsAccessTokenResponseClient() {
DefaultClientCredentialsTokenResponseClient accessTokenResponseClient =
new DefaultClientCredentialsTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2PasswordGrantRequest> passwordAccessTokenResponseClient() {
DefaultPasswordTokenResponseClient accessTokenResponseClient =
new DefaultPasswordTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerAccessTokenResponseClient() {
DefaultJwtBearerTokenResponseClient accessTokenResponseClient =
new DefaultJwtBearerTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
return accessTokenResponseClient;
}
@Bean
public RestTemplate restTemplate() {
// ...
}
}
----
A default `OAuth2AuthorizedClientManager` will be published automatically by Spring Security when one is not already provided.
[TIP]
====
Notice that we don't need to customize the `SecurityFilterChain` bean in this case, and can stick with the defaults.
If using Spring Boot with no additional customizations, we can actually omit the `SecurityFilterChain` bean entirely.
====
Prior to Spring Security 6.2, we had to ensure this customization was applied to both OAuth2 Login (if we are using this feature) and OAuth2 Client components.
We had to use both the Spring Security DSL (for the `authorization_code` grant) and publish a bean of type `OAuth2AuthorizedClientManager` for other grant types.
To understand what is being configured behind the scenes, here's what the configuration might have looked like:
[source,java]
----
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient =
new DefaultAuthorizationCodeTokenResponseClient();
accessTokenResponseClient.setRestOperations(restTemplate());
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.oauth2Login((oauth2Login) -> oauth2Login
.tokenEndpoint((tokenEndpoint) -> tokenEndpoint
.accessTokenResponseClient(accessTokenResponseClient)
)
)
.oauth2Client((oauth2Client) -> oauth2Client
.authorizationCodeGrant((authorizationCode) -> authorizationCode
.accessTokenResponseClient(accessTokenResponseClient)
)
);
return http.build();
}
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
DefaultRefreshTokenTokenResponseClient refreshTokenAccessTokenResponseClient =
new DefaultRefreshTokenTokenResponseClient();
refreshTokenAccessTokenResponseClient.setRestOperations(restTemplate());
DefaultClientCredentialsTokenResponseClient clientCredentialsAccessTokenResponseClient =
new DefaultClientCredentialsTokenResponseClient();
clientCredentialsAccessTokenResponseClient.setRestOperations(restTemplate());
DefaultPasswordTokenResponseClient passwordAccessTokenResponseClient =
new DefaultPasswordTokenResponseClient();
passwordAccessTokenResponseClient.setRestOperations(restTemplate());
DefaultJwtBearerTokenResponseClient jwtBearerAccessTokenResponseClient =
new DefaultJwtBearerTokenResponseClient();
jwtBearerAccessTokenResponseClient.setRestOperations(restTemplate());
JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider =
new JwtBearerOAuth2AuthorizedClientProvider();
jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerAccessTokenResponseClient);
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken((refreshToken) -> refreshToken
.accessTokenResponseClient(refreshTokenAccessTokenResponseClient)
)
.clientCredentials((clientCredentials) -> clientCredentials
.accessTokenResponseClient(clientCredentialsAccessTokenResponseClient)
)
.password((password) -> password
.accessTokenResponseClient(passwordAccessTokenResponseClient)
)
.provider(jwtBearerAuthorizedClientProvider)
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
public RestTemplate restTemplate() {
// ...
}
}
----
[[further-reading]]
== Further Reading
This preceding sections introduced Spring Security's support for OAuth2 with examples for common scenarios.
You can read more about OAuth2 Client and Resource Server in the following sections of the reference documentation:
* xref:servlet/oauth2/login/index.adoc[]
* xref:servlet/oauth2/client/index.adoc[]
* xref:servlet/oauth2/resource-server/index.adoc[]