Sending GET request with Authentication headers using restTemplate
Asked Answered
A

7

107

I need to retrieve resources from my server by sending a GET request with some Authorization headers using RestTemplate.

After going over the docs I noticed that none of the GET methods accepts headers as a parameter, and the only way to send Headers such as accept and Authorization is by using the exchange method.

Since it is a very basic action I am wondering if I am missing something and there another, easier way to do it?

Amorete answered 13/1, 2014 at 21:0 Comment(0)
M
76

You're not missing anything. RestTemplate#exchange(..) is the appropriate method to use to set request headers.

Here's an example (with POST, but just change that to GET and use the entity you want).

Here's another example.

Note that with a GET, your request entity doesn't have to contain anything (unless your API expects it, but that would go against the HTTP spec). It can be an empty String.

Medullary answered 13/1, 2014 at 21:2 Comment(0)
R
69

You can use postForObject with an HttpEntity. It would look like this:

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer "+accessToken);

HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String result = restTemplate.postForObject(url, entity, String.class);

In a GET request, you'd usually not send a body (it's allowed, but it doesn't serve any purpose). The way to add headers without wiring the RestTemplate differently is to use the exchange or execute methods directly. The get shorthands don't support header modification.

The asymmetry is a bit weird on a first glance, perhaps this is going to be fixed in future versions of Spring.

Ruben answered 30/12, 2015 at 16:6 Comment(2)
restTemplate.postForEntity(url, entity, String.class) also works fine.Fleshly
The question is about GET request, but this answer is about POST. It's misleading. There is no getForObject with such a signature.Countercharge
A
35

Here's a super-simple example with basic authentication, headers, and exception handling...

private HttpHeaders createHttpHeaders(String user, String password)
{
    String notEncoded = user + ":" + password;
    String encodedAuth = "Basic " + Base64.getEncoder().encodeToString(notEncoded.getBytes());
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    headers.add("Authorization", encodedAuth);
    return headers;
}

private void doYourThing() 
{
    String theUrl = "http://blah.blah.com:8080/rest/api/blah";
    RestTemplate restTemplate = new RestTemplate();
    try {
        HttpHeaders headers = createHttpHeaders("fred","1234");
        HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
        ResponseEntity<String> response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, String.class);
        System.out.println("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
    }
    catch (Exception eek) {
        System.out.println("** Exception: "+ eek.getMessage());
    }
}
Anthropomorphous answered 24/4, 2017 at 14:9 Comment(5)
Not sure why this was originally downvoted. If you're the first to downvote, feel free to explain in a comment.Finke
The "Basic " part should not be encoded, should it be ?Hedda
The createHttpHeaders method is slightly incorrect. String notEncoded = user + ":" + password; ... headers.add("Authorization", "Basic " + encodedAuth);Martyrology
I also just discovered that "Basic" shouldn't be encoded as well. This is a good example of how to do auth that I myself used, but correcting the encoding would be good.Brought
Fixed the Basic encoding mentioned in the comments aboveObstipation
B
19

These days something like the following will suffice:

HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
restTemplate.exchange(RequestEntity.get(new URI(url)).headers(headers).build(), returnType);
Boggess answered 29/6, 2020 at 21:59 Comment(0)
C
11

All of these answers appear to be incomplete and/or kludges. Looking at the RestTemplate interface, it sure looks like it is intended to have a ClientHttpRequestFactory injected into it, and then that requestFactory will be used to create the request, including any customizations of headers, body, and request params.

You either need a universal ClientHttpRequestFactory to inject into a single shared RestTemplate or else you need to get a new template instance via new RestTemplate(myHttpRequestFactory).

Unfortunately, it looks somewhat non-trivial to create such a factory, even when you just want to set a single Authorization header, which is pretty frustrating considering what a common requirement that likely is, but at least it allows easy use if, for example, your Authorization header can be created from data contained in a Spring-Security Authorization object, then you can create a factory that sets the outgoing AuthorizationHeader on every request by doing SecurityContextHolder.getContext().getAuthorization() and then populating the header, with null checks as appropriate. Now all outbound rest calls made with that RestTemplate will have the correct Authorization header.

Without more emphasis placed on the HttpClientFactory mechanism, providing simple-to-overload base classes for common cases like adding a single header to requests, most of the nice convenience methods of RestTemplate end up being a waste of time, since they can only rarely be used.

I'd like to see something simple like this made available

@Configuration
public class MyConfig {
  @Bean
  public RestTemplate getRestTemplate() {
    return new RestTemplate(new AbstractHeaderRewritingHttpClientFactory() {
        @Override
        public HttpHeaders modifyHeaders(HttpHeaders headers) {
          headers.addHeader("Authorization", computeAuthString());
          return headers;
        }
        public String computeAuthString() {
          // do something better than this, but you get the idea
          return SecurityContextHolder.getContext().getAuthorization().getCredential();
        }
    });
  }
}

At the moment, the interface of the available ClientHttpRequestFactory's are harder to interact with than that. Even better would be an abstract wrapper for existing factory implementations which makes them look like a simpler object like AbstractHeaderRewritingRequestFactory for the purposes of replacing just that one piece of functionality. Right now, they are very general purpose such that even writing those wrappers is a complex piece of research.

Catwalk answered 30/6, 2017 at 1:18 Comment(1)
While your "answer" is very interesting it reads more like a comment than an actual answer.Cleft
P
2

A simple solution would be to configure static http headers needed for all calls in the bean configuration of the RestTemplate:

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate getRestTemplate(@Value("${did-service.bearer-token}") String bearerToken) {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getInterceptors().add((request, body, clientHttpRequestExecution) -> {
            HttpHeaders headers = request.getHeaders();
            if (!headers.containsKey("Authorization")) {
                String token = bearerToken.toLowerCase().startsWith("bearer") ? bearerToken : "Bearer " + bearerToken;
                request.getHeaders().add("Authorization", token);
            }
            return clientHttpRequestExecution.execute(request, body);
        });
        return restTemplate;
    }
}
Puttergill answered 26/10, 2020 at 21:22 Comment(0)
J
0

NOTE: As of Spring 5 the RestTemplate class is in maintenance mode and its usage is not recommended. Whenever it is possible use WebClient.

That said, you may still need to configure a RestTemplate due to certain constraints with some frameworks or other reasons.

Instead of providing the authentication headers in each and every request, it would be better to configure a global RestTemplate so that it can be reused by different components.

Find below a configuration file with different approaches to provide the authentication headers.

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplateWithCustomApiKey(@Value("${api.key}") String apiKey) {
        return new RestTemplateBuilder()
                .requestCustomizers(clientHttpRequest -> clientHttpRequest.getHeaders().add("X-API-Key", apiKey))
                .build();
    }

    @Bean
    public RestTemplate restTemplateWithBearerTokenSupplier(JwtTokenProvider yourJwtTokenProvider) {
        return new RestTemplateBuilder()
                .requestCustomizers(clientHttpRequest -> clientHttpRequest.getHeaders().setBearerAuth(yourJwtTokenProvider.getAccessToken()))
                .build();
    }

    @Bean
    public RestTemplate restTemplateWithBasicAuth(@Value("${auth.user}") String user, @Value("${auth.pass}") String pass) {
        return new RestTemplateBuilder()
                .requestCustomizers(clientHttpRequest -> clientHttpRequest.getHeaders().setBasicAuth(user, pass))
                .build();
    }
}

Jaconet answered 3/10, 2023 at 8:51 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.