123 lines
3.7 KiB
Plaintext
123 lines
3.7 KiB
Plaintext
= OAuth 2.0 Resource Server Bearer Tokens
|
|
|
|
[[webflux-oauth2resourceserver-bearertoken-resolver]]
|
|
== Bearer Token Resolution
|
|
|
|
By default, Resource Server looks for a bearer token in the `Authorization` header.
|
|
This, however, can be customized.
|
|
|
|
For example, you may have a need to read the bearer token from a custom header.
|
|
To achieve this, you can wire an instance of `ServerBearerTokenAuthenticationConverter` into the DSL, as you can see in the following example:
|
|
|
|
.Custom Bearer Token Header
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
----
|
|
ServerBearerTokenAuthenticationConverter converter = new ServerBearerTokenAuthenticationConverter();
|
|
converter.setBearerTokenHeaderName(HttpHeaders.PROXY_AUTHORIZATION);
|
|
http
|
|
.oauth2ResourceServer(oauth2 -> oauth2
|
|
.bearerTokenConverter(converter)
|
|
);
|
|
----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
val converter = ServerBearerTokenAuthenticationConverter()
|
|
converter.setBearerTokenHeaderName(HttpHeaders.PROXY_AUTHORIZATION)
|
|
return http {
|
|
oauth2ResourceServer {
|
|
bearerTokenConverter = converter
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
== Bearer Token Propagation
|
|
|
|
Now that you're in possession of a bearer token, it might be handy to pass that to downstream services.
|
|
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:
|
|
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
----
|
|
@Bean
|
|
public WebClient rest() {
|
|
return WebClient.builder()
|
|
.filter(new ServerBearerExchangeFilterFunction())
|
|
.build();
|
|
}
|
|
----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
@Bean
|
|
fun rest(): WebClient {
|
|
return WebClient.builder()
|
|
.filter(ServerBearerExchangeFilterFunction())
|
|
.build()
|
|
}
|
|
----
|
|
====
|
|
|
|
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.
|
|
Then, it will propagate that token in the `Authorization` header.
|
|
|
|
For example:
|
|
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
----
|
|
this.rest.get()
|
|
.uri("https://other-service.example.com/endpoint")
|
|
.retrieve()
|
|
.bodyToMono(String.class)
|
|
----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
this.rest.get()
|
|
.uri("https://other-service.example.com/endpoint")
|
|
.retrieve()
|
|
.bodyToMono<String>()
|
|
----
|
|
====
|
|
|
|
Will invoke the `https://other-service.example.com/endpoint`, adding the bearer token `Authorization` header for you.
|
|
|
|
In places where you need to override this behavior, it's a simple matter of supplying the header yourself, like so:
|
|
|
|
====
|
|
.Java
|
|
[source,java,role="primary"]
|
|
----
|
|
this.rest.get()
|
|
.uri("https://other-service.example.com/endpoint")
|
|
.headers(headers -> headers.setBearerAuth(overridingToken))
|
|
.retrieve()
|
|
.bodyToMono(String.class)
|
|
----
|
|
|
|
.Kotlin
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
rest.get()
|
|
.uri("https://other-service.example.com/endpoint")
|
|
.headers { it.setBearerAuth(overridingToken) }
|
|
.retrieve()
|
|
.bodyToMono<String>()
|
|
----
|
|
====
|
|
|
|
In this case, the filter will fall back and simply forward the request onto the rest of the web filter chain.
|
|
|
|
[NOTE]
|
|
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.
|
|
To obtain this level of support, please use the OAuth 2.0 Client filter.
|