mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-11-04 00:28:54 +00:00 
			
		
		
		
	
		
			
	
	
		
			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.
							 |