Skip to content

Commit d59ab13

Browse files
committed
docs: add application-scoped access tokens example for reactive OAuth2 client
Signed-off-by: C0ng_yun <s25069@gsm.hs.kr>
1 parent 21978ca commit d59ab13

3 files changed

Lines changed: 156 additions & 5 deletions

File tree

docs/modules/ROOT/pages/reactive/oauth2/client/authorization-grants.adoc

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ class OAuth2ClientSecurityConfig {
340340
Please refer to the https://tools.ietf.org/html/rfc6749#section-4.1.3[Access Token Request/Response] protocol flow for the Authorization Code grant.
341341
====
342342

343-
The default implementation of `ReactiveOAuth2AccessTokenResponseClient` for the Authorization Code grant is `WebClientReactiveAuthorizationCodeTokenResponseClient`, which uses a `WebClient` for exchanging an authorization code for an access token at the Authorization Servers Token Endpoint.
343+
The default implementation of `ReactiveOAuth2AccessTokenResponseClient` for the Authorization Code grant is `WebClientReactiveAuthorizationCodeTokenResponseClient`, which uses a `WebClient` for exchanging an authorization code for an access token at the Authorization Server's Token Endpoint.
344344

345345
:section-id: authorization-code
346346
:grant-type: Authorization Code
@@ -432,7 +432,7 @@ Please refer to the OAuth 2.0 Authorization Framework for further details on the
432432
Please refer to the https://tools.ietf.org/html/rfc6749#section-6[Access Token Request/Response] protocol flow for the Refresh Token grant.
433433
====
434434

435-
The default implementation of `ReactiveOAuth2AccessTokenResponseClient` for the Refresh Token grant is `WebClientReactiveRefreshTokenTokenResponseClient`, which uses a `WebClient` when refreshing an access token at the Authorization Servers Token Endpoint.
435+
The default implementation of `ReactiveOAuth2AccessTokenResponseClient` for the Refresh Token grant is `WebClientReactiveRefreshTokenTokenResponseClient`, which uses a `WebClient` when refreshing an access token at the Authorization Server's Token Endpoint.
436436

437437
:section-id: refresh-token
438438
:grant-type: Refresh Token
@@ -512,7 +512,7 @@ Please refer to the OAuth 2.0 Authorization Framework for further details on the
512512
Please refer to the https://tools.ietf.org/html/rfc6749#section-4.4.2[Access Token Request/Response] protocol flow for the Client Credentials grant.
513513
====
514514

515-
The default implementation of `ReactiveOAuth2AccessTokenResponseClient` for the Client Credentials grant is `WebClientReactiveClientCredentialsTokenResponseClient`, which uses a `WebClient` when requesting an access token at the Authorization Servers Token Endpoint.
515+
The default implementation of `ReactiveOAuth2AccessTokenResponseClient` for the Client Credentials grant is `WebClientReactiveClientCredentialsTokenResponseClient`, which uses a `WebClient` when requesting an access token at the Authorization Server's Token Endpoint.
516516

517517
:section-id: client-credentials
518518
:grant-type: Client Credentials
@@ -698,6 +698,31 @@ class OAuth2ClientController {
698698
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`.
699699
====
700700

701+
[[oauth2-client-client-credentials-application-scoped]]
702+
=== Use the Client Credentials Grant for Application-Scoped Access Tokens
703+
704+
When making requests that are not associated with a specific user (e.g. background jobs, batch processes, or scheduled tasks), use `AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager` instead of `DefaultReactiveOAuth2AuthorizedClientManager`.
705+
Unlike `DefaultReactiveOAuth2AuthorizedClientManager`, `AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager` operates outside of a `ServerWebExchange` context, making it suitable for application-scoped access tokens.
706+
707+
The following example shows how to configure a `WebClient` for application-scoped access tokens using the Client Credentials grant:
708+
709+
.WebClient with Application-Scoped Access Tokens
710+
[tabs]
711+
======
712+
Java::
713+
+
714+
[source,java,role="primary",indent=0]
715+
----
716+
include::{tests-dir}/reactive/oauth2/webclient/ApplicationScopedAccessTokenConfiguration.java[tag=webclient-client-credentials]
717+
----
718+
======
719+
720+
[NOTE]
721+
====
722+
`AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager` uses a `ReactiveOAuth2AuthorizedClientService` to persist authorized clients, rather than a `ServerOAuth2AuthorizedClientRepository`.
723+
This makes it suitable for use cases where there is no active `ServerWebExchange`, such as background tasks or scheduled jobs.
724+
====
725+
701726
[[oauth2-client-jwt-bearer]]
702727
== JWT Bearer
703728

@@ -714,7 +739,7 @@ Please refer to JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication
714739
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.
715740
====
716741

717-
The default implementation of `ReactiveOAuth2AccessTokenResponseClient` for the JWT Bearer grant is `WebClientReactiveJwtBearerTokenResponseClient`, which uses a `WebClient` when requesting an access token at the Authorization Servers Token Endpoint.
742+
The default implementation of `ReactiveOAuth2AccessTokenResponseClient` for the JWT Bearer grant is `WebClientReactiveJwtBearerTokenResponseClient`, which uses a `WebClient` when requesting an access token at the Authorization Server's Token Endpoint.
718743

719744
:section-id: jwt-bearer
720745
:grant-type: JWT Bearer
@@ -922,7 +947,7 @@ Please refer to OAuth 2.0 Token Exchange for further details on the https://data
922947
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.
923948
====
924949

925-
The default implementation of `ReactiveOAuth2AccessTokenResponseClient` for the Token Exchange grant is `WebClientReactiveTokenExchangeTokenResponseClient`, which uses a `WebClient` when requesting an access token at the Authorization Servers Token Endpoint.
950+
The default implementation of `ReactiveOAuth2AccessTokenResponseClient` for the Token Exchange grant is `WebClientReactiveTokenExchangeTokenResponseClient`, which uses a `WebClient` when requesting an access token at the Authorization Server's Token Endpoint.
926951

927952
:section-id: token-exchange
928953
:grant-type: Token Exchange
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.docs.reactive.oauth2.webclient;
18+
19+
import org.springframework.context.annotation.Bean;
20+
import org.springframework.context.annotation.Configuration;
21+
import org.springframework.security.oauth2.client.AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager;
22+
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager;
23+
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientProviderBuilder;
24+
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
25+
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
26+
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
27+
import org.springframework.web.reactive.function.client.WebClient;
28+
29+
@Configuration
30+
public class ApplicationScopedAccessTokenConfiguration {
31+
32+
// tag::webclient-client-credentials[]
33+
@Bean
34+
ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
35+
ReactiveClientRegistrationRepository clientRegistrationRepository,
36+
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
37+
38+
var authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
39+
.clientCredentials()
40+
.build();
41+
42+
var authorizedClientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
43+
clientRegistrationRepository, authorizedClientService);
44+
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
45+
46+
return authorizedClientManager;
47+
}
48+
49+
@Bean
50+
WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
51+
var oauth2Client = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
52+
oauth2Client.setDefaultClientRegistrationId("my-client");
53+
54+
return WebClient.builder()
55+
.filter(oauth2Client)
56+
.build();
57+
}
58+
// end::webclient-client-credentials[]
59+
60+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2004-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.docs.reactive.oauth2.webclient;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.api.extension.ExtendWith;
21+
import org.mockito.Mockito;
22+
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.security.config.test.SpringTestContext;
27+
import org.springframework.security.config.test.SpringTestContextExtension;
28+
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
29+
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
30+
import org.springframework.web.reactive.function.client.WebClient;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
34+
/**
35+
* Tests {@link ApplicationScopedAccessTokenConfiguration}.
36+
*/
37+
@ExtendWith(SpringTestContextExtension.class)
38+
public class ApplicationScopedAccessTokenTests {
39+
40+
public final SpringTestContext spring = new SpringTestContext(this);
41+
42+
@Autowired
43+
WebClient webClient;
44+
45+
@Test
46+
void webClientWhenClientCredentialsThenConfigured() {
47+
this.spring.register(TestConfig.class, ApplicationScopedAccessTokenConfiguration.class).autowire();
48+
assertThat(this.webClient).isNotNull();
49+
}
50+
51+
@Configuration
52+
static class TestConfig {
53+
54+
@Bean
55+
ReactiveClientRegistrationRepository clientRegistrationRepository() {
56+
return Mockito.mock(ReactiveClientRegistrationRepository.class);
57+
}
58+
59+
@Bean
60+
ReactiveOAuth2AuthorizedClientService authorizedClientService() {
61+
return Mockito.mock(ReactiveOAuth2AuthorizedClientService.class);
62+
}
63+
64+
}
65+
66+
}

0 commit comments

Comments
 (0)