Spring OAuth2 Using Password Grant Type With Additional Headers Continued

Part 2 – Accessing a Resource

Recap

This is a continuation of the previous post that I made some time last month. You can start reading from there to get more context – https://www.joseyamut.xyz/2021/02/24/spring-oauth2-using-password-grant-type-with-additional-headers

The first part dealt with getting the access token from a 3rd party token service provider using a password grant. The token can then be used to access secured resources, like for example GET-ing some reporting data or POST-ing some additional data.

That was also all about an OAuth2 flow that does not really follow the usual pattern – point in case additional headers to go through a gateway or no user interaction on user login.

General Case

Now that I can get an access token, I can use it to have my application get access to restricted resources. Without it the app would not be allowed to do so. All that I need to do is to pass in that token in the header whenever a request is made to access said resource through a REST-ful API endpoint provided by a 3rd party.

The header will look something like,

Authorization: Bearer the-access-token-here

Normally, the Spring OAuth2 client that we are using will handle adding the access token in the headers automatically. I don’t have to do anything and can straight away use the many options such as the getForObject or postForEntity methods under the RestTemplate class, to name a few.

This means that I can just do the below and that’s it!

@Autowired
private OAuth2RestOperations restTemplate;

public void getSomething() {
        String resourceUri = "http://localhost:8080/path/to/foobar";
        ResponseEntity<String> response = restTemplate.getForEntity(resourceUri + "/1", String.class);
}

Alternative Use Case

As always, sometimes that is not as simple as it gets. There are cases where additional layers of security and customization comes in between. For example, there is a proxy/gateway in between my app and the 3rd party resource. This proxy/gateway takes in different headers for authentication (user login), and to handle passing on the authorization (token) to the 3rd party API endpoint.

On top of that the proxy/gateway changed the header purposes (Because it’s customized, what else?).

Well, don’t fret. This can certainly be solved via a quick solution.

Let’s say the custom proxy/gateway requires the following:

  • Authorization – header for Basic Authentication
  • X-Vendor-Token – header for the vendor access token

Simply put, the first header requirement asks my app for a proxy/gateway username and password. Then the second one requires it to include the token in the custom header name.

What I need to do now is to manipulate the headers sent to the resource. This can be done by intercepting the request to that resource endpoint. Fortunately, the RestTemplate class has this functionality with the use of Interceptors.

Defining a Custom Interceptor

I want to set the headers manually according to the proxy/gateway requirements.

My custom interceptor class will look like so:

public class CustomClientRequestInterceptor implements ClientHttpRequestInterceptor {

    private String basicAuthCredential;
    private String bearerToken;

    public String getBasicAuthCredential() {
        return basicAuthCredential;
    }

    public void setBasicAuthCredential(String basicAuthCredential) {
        this.basicAuthCredential = basicAuthCredential;
    }

    public String getBearerToken() {
        return bearerToken;
    }

    public void setBearerToken(String bearerToken) {
        this.bearerToken = bearerToken;
    }

    @Override
    public ClientHttpResponse intercept(
            HttpRequest request,
            byte[] body,
            ClientHttpRequestExecution execution) throws IOException {
        request.getHeaders().set("Authorization", this.basicAuthCredential);
        request.getHeaders().add("x-vendor-token", this.bearerToken);
        ClientHttpResponse response = execution.execute(request, body);
        return response;
    }
}

Breaking it down, I am extending the ClientHttpRequestInterceptor class so I can add in my own headers. All that is required is to override the intercept method and add/modify the required headers in there.

The HttpRequest object holds the headers when the request to the resource endpoint is made. This is what needs to be intercepted. Then I inject header information in it, before passing it on to the actual execution. Notice that for the Authorization header, I am SET-ing it instead of adding as new. The reason is that this request, before being intercepted, will already have that header in place. Remember, the OAuth2 client will have taken care of that for me. The second header – X-Vendor-Token – is being added on top since it is a new one.

Note: Do add some logic for checking if those header values have been properly defined when using the interceptor. I’m skipping those here for brevity.

Next Step

For the next step, I can then add the interceptor to an OAuth2 RestTemplate.

As shown in the first part (Refer to linked post at the beginning of this article), I will have configured an OAuth2RestOperations bean, similar to the one shown below:

    @Bean
    public OAuth2RestOperations restTemplate() {
        AccessTokenRequest tokenRequest = new DefaultAccessTokenRequest();
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resource, new DefaultOAuth2ClientContext(tokenRequest));

        /** set the Custom Request Interceptor here **/
        List<ClientHttpRequestInterceptor> interceptors
                = restTemplate.getInterceptors();
        if (CollectionUtils.isEmpty(interceptors)) {
            interceptors = new ArrayList<>();
        }

        CustomClientRequestInterceptor interceptor = new CustomClientRequestInterceptor();
        interceptor.setBasicAuthCredential("Basic auth-value");
        interceptor.setBearerToken("Bearer access-token");

        interceptors.add(interceptor);
        restTemplate.setInterceptors(interceptors);

        return restTemplate;
    }

Now I am all set. With the additional headers in place the request to the resource will allow the app to get the data needed.

An interceptor, on another hand, can be used for many other purposes of course. One that comes to mind is by modifying the response Content-Type header to something else. This is a fairly common use case. It can be used in conjunction to set the RestTemplate’s Message Converters. I’ll leave this topic for another post in the future.

Similar Posts: