Basic authentication for REST API using spring restTemplate
Asked Answered
V

12

123

I am completely new in RestTemplate and basically in the REST APIs also. I want to retrieve some data in my application via Jira REST API, but getting back 401 Unauthorised. Found and article on jira rest api documentation but don't really know how to rewrite this into java as the example uses the command line way with curl. I would appreciate any suggestion or advice how to rewrite:

curl -D- -X GET -H "Authorization: Basic ZnJlZDpmcmVk" -H "Content-Type: application/json" "http://kelpie9:8081/rest/api/2/issue/QA-31"

into java using spring rest template. Where the ZnJlZDpmcmVk is a base64 encoded string of username:password. Thank you very much.

Vulnerary answered 20/2, 2014 at 21:44 Comment(2)
See also #9377049Minute
curl supports authentication out of the box, you just need to tell it username and passoword curl -u fred:fred, no need for clunky manual headers. The same goes for Spring.Honorarium
C
192

Taken from the example on this site, I think this would be the most natural way of doing it, by filling in the header value and passing the header to the template.

This is to fill in the header Authorization:

String plainCreds = "willie:p@ssword";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);

HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);

And this is to pass the header to the REST template:

HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<Account> response = restTemplate.exchange(url, HttpMethod.GET, request, Account.class);
Account account = response.getBody();
Callant answered 20/2, 2014 at 21:50 Comment(3)
Thanks - this worked for me. I had to point out that if you do not want to use the org.apache.commons.codec.binary.Base64 class and you would like to use the android Base64 class instead: import android.util.Base64;, you can replace the one line above with this: byte[] base64CredsBytes = Base64.encode(plainCredsBytes, Base64.DEFAULT);Adrienneadrift
java 8 you can use Base64.getMimeEncoder().encodeToString()Dulcle
with HttpHeaders from spring-web:6.0.10, you can also write HttpHeaders requestHeaders = new HttpHeaders(); requestHeaders.setBasicAuth(user, password);`Iolite
A
126

You may use spring-boot RestTemplateBuilder

@Bean
RestOperations rest(RestTemplateBuilder restTemplateBuilder) {
    return restTemplateBuilder.basicAuthentication("user", "password").build();
}

See documentation

(before SB 2.1.0 it was #basicAuthorization)

Adiana answered 5/6, 2017 at 13:48 Comment(2)
Thanks! This is the fastest and easiest way.Cnemis
It is not a good solution as it would add an authorization header to each and every request sent through RestTemplate.Napolitano
N
53

There are multiple ways to add the basic HTTP authentication to the RestTemplate.

1. For a single request

try {
    // request url
    String url = "https://jsonplaceholder.typicode.com/posts";

    // create auth credentials
    String authStr = "username:password";
    String base64Creds = Base64.getEncoder().encodeToString(authStr.getBytes());

    // create headers
    HttpHeaders headers = new HttpHeaders();
    headers.add("Authorization", "Basic " + base64Creds);

    // create request
    HttpEntity request = new HttpEntity(headers);

    // make a request
    ResponseEntity<String> response = new RestTemplate().exchange(url, HttpMethod.GET, request, String.class);

    // get JSON response
    String json = response.getBody();

} catch (Exception ex) {
    ex.printStackTrace();
}

If you are using Spring 5.1 or higher, it is no longer required to manually set the authorization header. Use headers.setBasicAuth() method instead:

// create headers
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("username", "password");

2. For a group of requests

@Service
public class RestService {

    private final RestTemplate restTemplate;

    public RestService(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder
                .basicAuthentication("username", "password")
                .build();
    }

   // use `restTemplate` instance here
}

3. For each and every request

@Bean
RestOperations restTemplateBuilder(RestTemplateBuilder restTemplateBuilder) {
    return restTemplateBuilder.basicAuthentication("username", "password").build();
}

I hope it helps!

Napolitano answered 21/9, 2019 at 13:6 Comment(2)
Best answer. Each for it's kind.Romantic
Being on Spring 5.2 I just loved to see the phrase "If you are using Spring 5.1 or higher..." - yes please, finally!Arathorn
S
34

As of Spring 5.1 you can use HttpHeaders.setBasicAuth

Create Basic Authorization header:

String username = "willie";
String password = ":p@ssword";
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username, password);
...other headers goes here...

Pass the headers to the RestTemplate:

HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<Account> response = restTemplate.exchange(url, HttpMethod.GET, request, Account.class);
Account account = response.getBody();

Documentation: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpHeaders.html#setBasicAuth-java.lang.String-java.lang.String-

Selfdriven answered 20/11, 2018 at 14:16 Comment(0)
P
27

(maybe) the easiest way without importing spring-boot.

restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor("user", "password"));
Premillennialism answered 15/3, 2018 at 11:11 Comment(2)
Beware that using interceptors has a consequence that streaming no longer works. Here's why: exchange() -> doExecute(), -> createRequest(), -> InterceptingHttpAccessor.getRequestFactory() (since RestTemplate extends InterceptingHttpAccessor). If there are interceptors, getRequestFactory() returns an InterceptingClientHttpRequestFactory, which creates InterceptingClientHttpRequests. These extend AbstractBufferingClientHttpRequest`, which converts the input stream to a byte[] (to hand off to the interceptors). So, an InputStream is not actually streamed.Dovetailed
This approach is now deprecated. Use BasicAuthenticationInterceptor instead.Copalite
G
18

Reference Spring Boot's TestRestTemplate implementation as follows:

https://github.com/spring-projects/spring-boot/blob/v1.2.2.RELEASE/spring-boot/src/main/java/org/springframework/boot/test/TestRestTemplate.java

Especially, see the addAuthentication() method as follows:

private void addAuthentication(String username, String password) {
    if (username == null) {
        return;
    }
    List<ClientHttpRequestInterceptor> interceptors = Collections
            .<ClientHttpRequestInterceptor> singletonList(new BasicAuthorizationInterceptor(
                    username, password));
    setRequestFactory(new InterceptingClientHttpRequestFactory(getRequestFactory(),
            interceptors));
}

Similarly, you can make your own RestTemplate easily

by inheritance like TestRestTemplate as follows:

https://github.com/izeye/samples-spring-boot-branches/blob/rest-and-actuator-with-security/src/main/java/samples/springboot/util/BasicAuthRestTemplate.java

Ghee answered 11/3, 2015 at 7:54 Comment(0)
L
6

Instead of instantiating as follows:

TestRestTemplate restTemplate = new TestRestTemplate();

Just do it like this:

TestRestTemplate restTemplate = new TestRestTemplate(user, password);

It works for me, I hope it helps!

Lian answered 22/1, 2016 at 13:14 Comment(2)
TestRestTemplate doesn't seem to working after upgrading spring boot to 1.3.xLedezma
Isn't this supposed to be used for unit tests not release code?Fairchild
J
3
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username, password);

then continue with the same procedure mentioned by the others here:

HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, request, String.class);
Jurel answered 18/11, 2021 at 8:38 Comment(1)
This seems to be pretty much just a repeat of this existing answer.Hellenic
S
1

Use setBasicAuth to define credentials

HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("myUsername", myPassword);

Then create the request like you prefer.

Example:

HttpEntity<String> request = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, 
request, String.class);
String body = response.getBody();
Sordid answered 10/9, 2020 at 18:0 Comment(1)
Dublicate of stackoverflow.com/a/53394971 answerVictualler
S
0

I'm using spring version 5.3.15 for my unit test environment. I used withBasicAuth for my tests :

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyTestClass {
    ...
    @Autowired
    private TestRestTemplate restTemplate;
    ...
    @Test
    @SneakyThrows
    public void TestGetSettings(){
        DtoClass dtoClass  = this.restTemplate
                           .withBasicAuth(UserServices.DEFAULT_USER, UserServices.DEFAULT_PASSWORD)
                           .getForObject(String.format("http://localhost:%d/setting",
                port), DtoClass.class);
        assertThat(dtoClass.getClientAddress()).isNotEmpty();
    }
   ...
}

As you see this method only work for basic authentication. If you look at the details of the withBasicAuth method, you will find that the method source will be like this:

// TestRestTemplate.java file: 
...
public class TestRestTemplate {
    ... 
    private final RestTemplateBuilder builder;
    ...
    public TestRestTemplate withBasicAuth(String username, String password) {
      TestRestTemplate template = new TestRestTemplate(this.builder, username, password, this.httpClientOptions);
      ...
    }
}

As a result, for other types of authentication you can use the RestTemplateBuilder as a builder which is mentioned in other answers.

Surgy answered 14/5, 2022 at 12:10 Comment(0)
E
0

Follow Step By Step

I added Client Credentials In application.Properties file like below...

http.basicauth.username = yourUserName
http.basicauth.password = yourPassword

And , Then I created one class With two fields Because I'm loading those two fields from the Application.Properties file : username and password . Make sure your class is annotated with @Component..

@Value("${http.basicauth.username}")
private String username;

@Value("${http.basicauth.password}")
private String password;

And Then , You need to autowired above class From Wherever you want..

// I'm getting a username and password from application.properties file 
String userCredentials = referenceClassName.getUsername()+":"+referenceClassName.getPassword();
// Encoded User Credentials and Convert it into a String                        
String encodedUserCredentials= Base64.getMimeEncoder().encodeToString(userCredentialsBytes.getBytes());        
headers.set("Authorization", "Basic " +base64UserCredentials);

HttpEntity request = new HttpEntity(headers);
String url = "externalUrl";
// Getting a Json String body
String body = restTemplate.exchange(url,HttpMethod.GET,request,String.class).getBody();

 Note :: For getting an Access Token from String Json body  , That's why  I converted it into a Json Object
 JsonObject tokenJsonObject = new JsonParser().parse(body).getAsJsonObject();
// Getting access token as string from tokenJsonObject
String accessToken = tokenJsonObject.has("access_token") && !tokenJsonObject.get("access_token").isJsonNull() ? tokenJsonObject.get("access_token").getAsString() : "";

If you have any concerns, please let me know in comments..Hope It will helpful to you..

Equanimity answered 31/10, 2022 at 16:18 Comment(0)
M
0

I have been using Spring above 5.1.x

// create headers for basic auth

var headers = new HttpHeaders();
headers.setBasicAuth("username", "password");
Myth answered 22/11, 2022 at 11:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.