Skip to content

Commit 124d996

Browse files
committed
Document Bearer Token Propagation
Fixes gh-7461
1 parent 3a9ee46 commit 124d996

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

docs/manual/src/docs/asciidoc/_includes/reactive/oauth2/resource-server.adoc

+46
Original file line numberDiff line numberDiff line change
@@ -1000,3 +1000,49 @@ ReactiveOpaqueTokenIntrospector introspector() {
10001000
}
10011001
----
10021002

1003+
== Bearer Token Propagation
1004+
1005+
Now that you're in possession of a bearer token, it might be handy to pass that to downstream services.
1006+
This is quite simple with `{security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServerBearerExchangeFilterFunction.html[ServerBearerExchangeFilterFunction]`, which you can see in the following example:
1007+
1008+
[source,java]
1009+
----
1010+
@Bean
1011+
public WebClient rest() {
1012+
return WebClient.builder()
1013+
.filter(new ServerBearerExchangeFilterFunction())
1014+
.build();
1015+
}
1016+
----
1017+
1018+
When the above `WebClient` is used to perform requests, Spring Security will look up the current `Authentication` and extract any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[AbstractOAuth2Token]` credential.
1019+
Then, it will propagate that token in the `Authorization` header.
1020+
1021+
For example:
1022+
1023+
[source,java]
1024+
----
1025+
this.rest.get()
1026+
.uri("https://other-service.example.com/endpoint")
1027+
.retrieve()
1028+
.bodyToMono(String.class)
1029+
----
1030+
1031+
Will invoke the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you.
1032+
1033+
In places where you need to override this behavior, it's a simple matter of supplying the header yourself, like so:
1034+
1035+
[source,java]
1036+
----
1037+
this.rest.get()
1038+
.uri("https://other-service.example.com/endpoint")
1039+
.headers(headers -> headers.setBearerAuth(overridingToken))
1040+
.retrieve()
1041+
.bodyToMono(String.class)
1042+
----
1043+
1044+
In this case, the filter will fall back and simply forward the request onto the rest of the web filter chain.
1045+
1046+
[NOTE]
1047+
Unlike the https://docs.spring.io/spring-security/site/docs/current-SNAPSHOT/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServerOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired.
1048+
To obtain this level of support, please use the OAuth 2.0 Client filter.

docs/manual/src/docs/asciidoc/_includes/servlet/preface/oauth2-resourceserver.adoc

+76
Original file line numberDiff line numberDiff line change
@@ -1150,3 +1150,79 @@ OpaqueTokenIntrospector introspector() {
11501150

11511151
Thus far we have only taken a look at the most basic authentication configuration.
11521152
Let's take a look at a few slightly more advanced options for configuring authentication.
1153+
1154+
=== Bearer Token Propagation
1155+
1156+
Now that you're in possession of a bearer token, it might be handy to pass that to downstream services.
1157+
This is quite simple with `{security-api-url}org/springframework/security/oauth2/server/resource/web/reactive/function/client/ServletBearerExchangeFilterFunction.html[ServletBearerExchangeFilterFunction]`, which you can see in the following example:
1158+
1159+
[source,java]
1160+
----
1161+
@Bean
1162+
public WebClient rest() {
1163+
return WebClient.builder()
1164+
.filter(new ServletBearerExchangeFilterFunction())
1165+
.build();
1166+
}
1167+
----
1168+
1169+
When the above `WebClient` is used to perform requests, Spring Security will look up the current `Authentication` and extract any `{security-api-url}org/springframework/security/oauth2/core/AbstractOAuth2Token.html[AbstractOAuth2Token]` credential.
1170+
Then, it will propagate that token in the `Authorization` header.
1171+
1172+
For example:
1173+
1174+
[source,java]
1175+
----
1176+
this.rest.get()
1177+
.uri("https://other-service.example.com/endpoint")
1178+
.retrieve()
1179+
.bodyToMono(String.class)
1180+
.block()
1181+
----
1182+
1183+
Will invoke the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you.
1184+
1185+
In places where you need to override this behavior, it's a simple matter of supplying the header yourself, like so:
1186+
1187+
[source,java]
1188+
----
1189+
this.rest.get()
1190+
.uri("https://other-service.example.com/endpoint")
1191+
.headers(headers -> headers.setBearerAuth(overridingToken))
1192+
.retrieve()
1193+
.bodyToMono(String.class)
1194+
.block()
1195+
----
1196+
1197+
In this case, the filter will fall back and simply forward the request onto the rest of the web filter chain.
1198+
1199+
[NOTE]
1200+
Unlike the https://docs.spring.io/spring-security/site/docs/current-SNAPSHOT/api/org/springframework/security/oauth2/client/web/reactive/function/client/ServletOAuth2AuthorizedClientExchangeFilterFunction.html[OAuth 2.0 Client filter function], this filter function makes no attempt to renew the token, should it be expired.
1201+
To obtain this level of support, please use the OAuth 2.0 Client filter.
1202+
1203+
==== `RestTemplate` support
1204+
1205+
There is no dedicated support for `RestTemplate` at the moment, but you can achieve propagation quite simply with your own interceptor:
1206+
1207+
[source,java]
1208+
----
1209+
@Bean
1210+
RestTemplate rest() {
1211+
RestTemplate rest = new RestTemplate();
1212+
rest.getInterceptors().add((request, body, execution) -> {
1213+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
1214+
if (authentication == null) {
1215+
return execution.execute(request, body);
1216+
}
1217+
1218+
if (!(authentication.getCredentials() instanceof AbstractOAuth2Token)) {
1219+
return execution.execute(request, body);
1220+
}
1221+
1222+
AbstractOAuth2Token token = (AbstractOAuth2Token) authentication.getCredentials();
1223+
request.getHeaders().setBearerAuth(token.getTokenValue());
1224+
return execution.execute(request, body);
1225+
});
1226+
return rest;
1227+
}
1228+
----

0 commit comments

Comments
 (0)