Let’s say you want to call an OAuth2 protected microservice from your Spring Boot microservice application.
Spring Boot as usual does majority of the work for us.
We just need to add a dependency ,some configuration and using a single HTTP call using Spring Web Client we can invoke the microservice.
Before that , to know how to protect a microservice using OAuth2 refer this post.
To invoke a OAuth2 protected resource follow these steps:
STEP 1: Add required dependencies
STEP 2: Add required configuration in application.yml
STEP 3: Build a custom WebClient
STEP 4: Test
STEP 1: Add required dependencies:
The following three dependencies are required :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
When you add spring-boot-starter-oauth2-client Spring will assume that you are going to make OAuth2 calls and so will expect certain configuration in application.yml.
The next step explores that:
STEP 2: Add required configuration in application.yml
To call an OAuth2 protected resource ,you need an access token.
This access token is appended in the header when you make the actual call to the protected resource.
To get this token you need to make a call to the authorization server.
This call will be made automatically by Spring. It will automatically append the access token in all the calls made by your WebClient.
For this ,you need to give the information to Spring to make the access token call.
You need to specify the following:
- client id
- client secret
- authorization type (this will be a constant “client_credentials” as for microservices this is the preferred authorization type)
- scope if you have configured it on the authorization server else you can leave this.
- Token URL (this is the API which will generate the token)
- Issuer URL (this is the authorization server url along with the realm info that you configure on the authorization server)
Here is a sample:
server:
port: 8081
spring:
security:
oauth2:
client:
registration:
mywebclient:
client-id: myclient
client-secret: Wna8BGXiGIhmnzr7T1UQKb2260ruZhWB
authorization-grant-type: client_credentials
provider:
mywebclient:
issuer-uri: http://localhost:8080/realms/myrealm
token-uri: http://localhost:8080/realms/myrealm/protocol/openid-connect/token
In the above configuration “mywebclient” is the name we give to our oauth2 client. Rest all are predefined properties of Spring .We just need to feed the values.
You can obtain these values from your authorization server as explained step 6 in this post.
Once this configuration is done you need to build a WebClient spring bean with a filter.
This filter will filter all calls made by your WebClient and append an OAuth2 token to it.
This is explored in next step.
STEP 3: Build a custom Web Client
As earlier mentioned you need to add a filter to your webclient.
You can configure your web client centrally or for each REST API call you make you can add the filter.
In this post we will explore the former option.
Let’s do this step by step since the creation of a custom web client looks a bit complex:
We need a web client like this:
WebClient.builder().apply(filter.oauth2Configuration()).build();
Notice that we are applying oauth2 configuration from a filter here.
Here is the filter to be used:
ServletOAuth2AuthorizedClientExchangeFilterFunction filter = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
authorizedClientManager);
filter.setDefaultClientRegistrationId("mywebclient");
We also need to set the oauth2 client name which we configured in application.yml as shown above.
Now we have the filter.
Let’s create a WebClient bean:
@Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction filter = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
authorizedClientManager);
filter.setDefaultClientRegistrationId("mywebclient");
return WebClient.builder().apply(filter.oauth2Configuration()).build();
}
The above method creates a WebClient bean.
Spring expects an OAuth2AuthorizedClientManager as a dependency.
To satisfy that create a client manager :
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager = new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
The above method takes two arguments which are automatically injected by Spring. You don’t need to define those beans.
The full configuration here:
package app.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientOAuth2Config {
@Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction filter = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
authorizedClientManager);
filter.setDefaultClientRegistrationId("mywebclient");
return WebClient.builder().apply(filter.oauth2Configuration()).build();
}
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager = new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}
Once this is configured we should be ready.
But here comes an issue ,this looks like a bug in Spring.
Since we added the spring-boot-starter-oauth2-client dependency Spring expects that your current microservice will also be protected by OAuth2. So if you create a REST API in your current microservice it will be automatically protected by OAuth2.
To disable this add a configuration which permits all requests to your client microservice:
package app.example;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("*").permitAll();
}
}
That’s it!
Now let’s test our changes.
STEP 4: Test
To test our changes let’s create a simple REST API .
We will call an oauth2 protected REST API from this API:
package app.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
@RestController
public class TestController {
@Autowired
private WebClient webClient;
@GetMapping("/test")
public String test() {
return webClient.get().uri("http://localhost:8085/test").retrieve().bodyToMono(String.class).block();
}
}
As you notice I am invoking an API (http://localhost:8085/test – refer this post to create this API). This is protected by OAuth2. It just returns a string message “success”.
I have autowired WebClient. The custom web client we created will be injected here by Spring.
And the access token will be automatically appended!
I deployed the service on port 8081.
Here is the response:

It worked!
We just made a single call and Spring automatically got the access token and appended it to this call.
Here is the entire code:
Leave a Reply