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:
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:
public interface UserService{ List<User> getUsers(); }
The implementation:
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("[email protected]"); User user2 = new User(); user2.setFirstName("Muhammad"); user2.setLastName("Ali"); user2.setEmail("[email protected]"); 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:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>3.0.2</version> </dependency>
For Gradle:
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.
@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.
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.
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:
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: [email protected] User Name: Muhammad Ali Email: [email protected]
Thanks for following the tutorial till the end. I hope that this adds to your knowledge.
Happy learning!