RestTemplate Example with Basic Authentication

This tutorial will teach you how to leverage RestTemplate to access RESTful APIs protected by basic authentication. You will learn to create a Basic Authentication-secured REST API and access it via RestTemplate.

What is Basic Authentication

As the name suggests, it is a basic form of authentication in which we must provide the correct username and password to access a resource.

What is RestTemplate

Simply put, it is a client provided by Spring to perform synchronous HTTP requests to consume a REST-based API endpoint. It provides templates for some common scenarios and is therefore named as RestTemplate.

Rest API Setup

Initially, I’ll demonstrate a straightforward REST API example for retrieving users from a fake API endpoint. Afterward, I’ll use Basic Authentication to secure this REST API. Finally, I will demonstrate how to call this REST API using Basic Authentication via Rest Template.

The following is the REST controller class for this API to retrieve users:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.security.UserService.UserService;
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "/user/", method = RequestMethod.GET)
public ResponseEntity<List<User>> listAllUsers() {
List<User> users = userService.getUsers();
if (users.isEmpty()) {
return new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(users, HttpStatus.OK);
}
}
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.security.UserService.UserService; @RestController public class UserController { @Autowired private UserService userService; @RequestMapping(value = "/user/", method = RequestMethod.GET) public ResponseEntity<List<User>> listAllUsers() { List<User> users = userService.getUsers(); if (users.isEmpty()) { return new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT); } return new ResponseEntity<>(users, HttpStatus.OK); } }
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.security.UserService.UserService;

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping(value = "/user/", method = RequestMethod.GET)
    public ResponseEntity<List<User>> listAllUsers() {
        List<User> users = userService.getUsers();
        if (users.isEmpty()) {
            return new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT);
        }
        return new ResponseEntity<>(users, HttpStatus.OK);
    }
}

Our UserService Interface will look like the following:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
public interface UserService{
List<User> getUsers();
}
public interface UserService{ List<User> getUsers(); }
public interface UserService{
    List<User> getUsers();
}

The implementation:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import java.util.Arrays;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Override
public List<User> getUsers() {
User user1 = new User();
user1.setFirstName("John");
user1.setLastName("Doe");
user1.setEmail("john.doe@mail.com");
User user2 = new User();
user2.setFirstName("Muhammad");
user2.setLastName("Ali");
user2.setEmail("muhammad.ali@mail.com");
return new ArrayList<>(Arrays.asList(user1, user2));
}
}
import java.util.Arrays; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Override public List<User> getUsers() { User user1 = new User(); user1.setFirstName("John"); user1.setLastName("Doe"); user1.setEmail("john.doe@mail.com"); User user2 = new User(); user2.setFirstName("Muhammad"); user2.setLastName("Ali"); user2.setEmail("muhammad.ali@mail.com"); return new ArrayList<>(Arrays.asList(user1, user2)); } }
import java.util.Arrays;

import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Override
    public List<User> getUsers() {
        User user1 = new User();
        user1.setFirstName("John");
        user1.setLastName("Doe");
        user1.setEmail("john.doe@mail.com");

        User user2 = new User();
        user2.setFirstName("Muhammad");
        user2.setLastName("Ali");
        user2.setEmail("muhammad.ali@mail.com");

        return new ArrayList<>(Arrays.asList(user1, user2));
    }
}

With this, we have an API ready, but it isn’t secured.

Securing API with Basic Authentication

To secure the API, we must first add Spring Security to our project.

For Maven:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>3.0.2</version>
</dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>3.0.2</version> </dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>3.0.2</version>
</dependency>

For Gradle:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '3.0.2'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '3.0.2'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '3.0.2'

As soon as we add the above dependency to our application, we will get a 401 unauthorized error by default on access.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@SpringBootApplication
public class RestBasicAuthApplication
{
public static void main(String[] args)
{
SpringApplication.run(RestBasicAuthApplication.class, args);
}
}
@SpringBootApplication public class RestBasicAuthApplication { public static void main(String[] args) { SpringApplication.run(RestBasicAuthApplication.class, args); } }
@SpringBootApplication
public class RestBasicAuthApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(RestBasicAuthApplication.class, args);
    }
}

To allow a user to access the API endpoint, we have to create a configuration class that will have the @EnableWebSecurity annotation and provides Spring the SecurityFilterChain and InMemoryUserDetailsManager beans required for authorization and authentication.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.
authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated()
)
.httpBasic();
return http.build();
}
@Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User
.withUsername("admin")
.password(passwordEncoder().encode("admin123"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http. authorizeHttpRequests((authz) -> authz .anyRequest().authenticated() ) .httpBasic(); return http.build(); } @Bean public InMemoryUserDetailsManager userDetailsService() { UserDetails user = User .withUsername("admin") .password(passwordEncoder().encode("admin123")) .roles("ADMIN") .build(); return new InMemoryUserDetailsManager(user); } @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.
                authorizeHttpRequests((authz) -> authz
                        .anyRequest().authenticated()
                )
                .httpBasic();
        return http.build();
    }

    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        UserDetails user = User
                .withUsername("admin")
                .password(passwordEncoder().encode("admin123"))
                .roles("ADMIN")
                .build();

        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

The InMemoryUserDetailsManager is setting the credentials for Basic Auth, and the SecurityFilterChain bean is set to authorize any request and set the authentication type to Basic Auth.

Finally, the PasswordEncoder bean helps decrypt the password and then store it in memory, without which Spring will warn us that our password is not encrypted.

Consuming an API secured with Basic Authentication via RestTemplate

Now we’ll create a client class to access our API programmatically.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import java.awt.PageAttributes.MediaType;
import java.net.http.HttpHeaders;
import java.util.Arrays;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.List;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
public class RestTemplateClient {
public static final String REST_SERVICE_URL = "http://localhost:8080/user/";
private static HttpHeaders httpHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Authorization", "Basic " + getBasicAuthHeader());
httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
return httpHeaders;
}
private static String getBasicAuthHeader() {
String credentials = "admin:admin123";
return new String(Base64.encodeBase64(credentials.getBytes()));
}
private static void listUserName() {
ResponseEntity<List> responseEntity = new RestTemplate().exchange(REST_SERVICE_URL,
HttpMethod.GET, new HttpEntity<>(httpHeaders()), List.class);
if (responseEntity.hasBody()) {
List<LinkedHashMap<String, Object>> users = responseEntity.getBody();
for (LinkedHashMap<String, Object> userMap : users) {
System.out.println("User Name: " + userMap.get("firstName") + " " + userMap.get("lastName"));
System.out.println("Email: " + userMap.get("email"));
}
}
}
public static void main(String[] args) {
listUserName();
}
}
import java.awt.PageAttributes.MediaType; import java.net.http.HttpHeaders; import java.util.Arrays; import java.util.Base64; import java.util.LinkedHashMap; import java.util.List; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; public class RestTemplateClient { public static final String REST_SERVICE_URL = "http://localhost:8080/user/"; private static HttpHeaders httpHeaders() { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add("Authorization", "Basic " + getBasicAuthHeader()); httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); return httpHeaders; } private static String getBasicAuthHeader() { String credentials = "admin:admin123"; return new String(Base64.encodeBase64(credentials.getBytes())); } private static void listUserName() { ResponseEntity<List> responseEntity = new RestTemplate().exchange(REST_SERVICE_URL, HttpMethod.GET, new HttpEntity<>(httpHeaders()), List.class); if (responseEntity.hasBody()) { List<LinkedHashMap<String, Object>> users = responseEntity.getBody(); for (LinkedHashMap<String, Object> userMap : users) { System.out.println("User Name: " + userMap.get("firstName") + " " + userMap.get("lastName")); System.out.println("Email: " + userMap.get("email")); } } } public static void main(String[] args) { listUserName(); } }
import java.awt.PageAttributes.MediaType;
import java.net.http.HttpHeaders;
import java.util.Arrays;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.List;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

public class RestTemplateClient {
    public static final String REST_SERVICE_URL = "http://localhost:8080/user/";

    private static HttpHeaders httpHeaders() {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Authorization", "Basic " + getBasicAuthHeader());
        httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        return httpHeaders;
    }

    private static String getBasicAuthHeader() {
        String credentials = "admin:admin123";
        return new String(Base64.encodeBase64(credentials.getBytes()));
    }

    private static void listUserName() {
        ResponseEntity<List> responseEntity = new RestTemplate().exchange(REST_SERVICE_URL,
                HttpMethod.GET, new HttpEntity<>(httpHeaders()), List.class);

        if (responseEntity.hasBody()) {
            List<LinkedHashMap<String, Object>> users = responseEntity.getBody();

            for (LinkedHashMap<String, Object> userMap : users) {
                System.out.println("User Name: " + userMap.get("firstName") + " " + userMap.get("lastName"));
                System.out.println("Email: " + userMap.get("email"));
            }
        }
    }

    public static void main(String[] args) {
        listUserName();
    }
}

The getBasicAuthHeader() returns a Base64 encoded string of the Basic Auth credentials, which we add to the HttpHeaders. HttpHeaders are then included in the GET request. We are consuming our API using RestTemplate.exchange() method.

Following is the output:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
19:31:25.128 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:8080/user/
19:31:25.214 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[application/json, application/*+json]
19:31:25.803 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
19:31:25.815 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.util.List<?>]
User Name: John Doe
Email: john.doe@mail.com
User Name: Muhammad Ali
Email: muhammad.ali@mail.com
19:31:25.128 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:8080/user/ 19:31:25.214 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[application/json, application/*+json] 19:31:25.803 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK 19:31:25.815 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.util.List<?>] User Name: John Doe Email: john.doe@mail.com User Name: Muhammad Ali Email: muhammad.ali@mail.com
19:31:25.128 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:8080/user/
19:31:25.214 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[application/json, application/*+json]
19:31:25.803 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
19:31:25.815 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [java.util.List<?>]
User Name: John Doe
Email: john.doe@mail.com
User Name: Muhammad Ali
Email: muhammad.ali@mail.com

Thanks for following the tutorial till the end. I hope that this adds to your knowledge.

Happy learning!