Communicating between microservices is a fundamental aspect of modern application development. Often, these services need to be secured. One of the simplest and most widely supported methods for securing REST APIs is Basic Authentication. In this guide, we’ll walk through how to configure and use Spring Boot’s RestTemplate to consume a REST API protected with Basic Auth.
We’ll cover the modern, recommended approach using Spring Security’s component-based configuration, updating older patterns you might find in other tutorials.
Project Setup
First, ensure your Spring Boot project includes the spring-boot-starter-web dependency. This starter conveniently bundles everything we need, including Spring MVC for creating the REST service, Tomcat as the embedded server, and RestTemplate support.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
You’ll also need the spring-boot-starter-security dependency to enable security features.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Step 1: Create a Secured REST Endpoint
Let’s start by creating a simple REST endpoint that we want to secure. This endpoint will return a greeting message. Without proper authentication, any request to this endpoint should be denied.
package com.ankurm.examples.rest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SecuredController {
@GetMapping("/api/hello")
public String getSecuredGreeting() {
return "Hello, you have accessed a secured endpoint!";
}
}
Step 2: Configure Spring Security for Basic Authentication
With Spring Security on the classpath, all endpoints are secured by default. Now, we need to configure it to use Basic Authentication and define a valid user.
As of Spring Security 5.7+, WebSecurityConfigurerAdapter is deprecated. The modern, recommended approach is to define a SecurityFilterChain bean. This makes the configuration more modular and easier to read.
Let’s create a configuration class to set up our security rules and an in-memory user.
package com.ankurm.examples.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class AppSecurityConfig {
// 1. Define the SecurityFilterChain bean
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // Disabling CSRF for stateless REST APIs
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/**").authenticated() // Secure all endpoints under /api/
.anyRequest().permitAll() // Allow all other requests
)
.httpBasic(Customizer.withDefaults()); // Enable HTTP Basic Authentication
return http.build();
}
// 2. Define an in-memory user for demonstration
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("admin")
.password("{noop}password123") // {noop} indicates plain text password (for demo only!)
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user);
}
}
Understanding the Security Configuration:
@EnableWebSecurity: Enables Spring Security’s web security support.securityFilterChain(HttpSecurity http): This bean defines the core security rules..csrf(csrf -> csrf.disable()): We disable Cross-Site Request Forgery (CSRF) protection, which is common for stateless REST APIs consumed by non-browser clients..authorizeHttpRequests(...): This is where we define which paths are secured. We specify that any request to/api/**must be authenticated..httpBasic(...): This explicitly enables the Basic Authentication scheme.
userDetailsService(): This bean sets up an in-memory user store. We create a user with the usernameadminand passwordpassword123. The{noop}prefix tells Spring Security that the password is not encoded and should be treated as plain text. This is for demonstration purposes only. In a production environment, you must always use a password encoder like BCrypt.
Step 3: Configure RestTemplate with Basic Auth Credentials
Now for the client side. We need to create a RestTemplate bean that is pre-configured to send the Basic Auth credentials with every request. The most idiomatic Spring Boot way to do this is by using the RestTemplateBuilder.
Let’s add this bean to a configuration class.
package com.ankurm.examples.config;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestClientConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.basicAuthentication("admin", "password123")
.build();
}
}
This is incredibly clean and readable. The .basicAuthentication("admin", "password123") method configures the underlying client to automatically add the Authorization header with the Base64-encoded credentials for every request made by this RestTemplate instance.
Step 4: Putting It All Together and Testing
To see our client in action, let’s create a CommandLineRunner. This is a simple component that runs its code once the Spring Boot application has started. We’ll inject our configured RestTemplate and use it to call our secured endpoint.
package com.ankurm.examples;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.HttpClientErrorException;
@Component
public class ApiClientRunner implements CommandLineRunner {
private static final Logger LOG = LoggerFactory.getLogger(ApiClientRunner.class);
private final RestTemplate restTemplate;
public ApiClientRunner(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public void run(String... args) {
LOG.info("...::: Starting REST API Client Test :::...");
try {
String apiUrl = "http://localhost:8080/api/hello";
ResponseEntity<String> response = restTemplate.getForEntity(apiUrl, String.class);
if (response.getStatusCode().is2xxSuccessful()) {
LOG.info("Success! Received response: {}", response.getBody());
}
} catch (HttpClientErrorException e) {
LOG.error("Error accessing API: {} - {}", e.getStatusCode(), e.getStatusText());
LOG.error("Response Body: {}", e.getResponseBodyAsString());
} catch (Exception e) {
LOG.error("An unexpected error occurred", e);
}
LOG.info("...::: REST API Client Test Finished :::...");
}
}
Running the Application
Now, run your Spring Boot application. When it starts, the ApiClientRunner will execute. You should see output in your console similar to this:
...
...::: Starting REST API Client Test :::...
... Success! Received response: Hello, you have accessed a secured endpoint!
...::: REST API Client Test Finished :::...
...
This confirms that our pre-configured RestTemplate successfully authenticated against the secured endpoint and received the expected response.
Alternative Method: Using a ClientHttpRequestInterceptor
While RestTemplateBuilder is preferred, another way to achieve the same result is by using a ClientHttpRequestInterceptor. This approach is more manual but can be useful if you need to add the authentication logic to an existing RestTemplate instance or require more complex conditional logic.
The BasicAuthenticationInterceptor does exactly what we need.
package com.ankurm.examples.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestClientConfigWithInterceptor {
// A different way to create the same configured RestTemplate
@Bean
public RestTemplate restTemplateWithInterceptor() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(
new BasicAuthenticationInterceptor("admin", "password123"));
return restTemplate;
}
}
To use this bean, you would need to inject it into your client component, for example, by using Spring’s @Qualifier("restTemplateWithInterceptor") annotation. The end result is identical to the RestTemplateBuilder method.
Conclusion
In this guide, we successfully demonstrated how to consume a Basic Auth-secured REST API using Spring Boot’s RestTemplate. We saw two effective methods:
- Using
RestTemplateBuilder: The modern, clean, and recommended approach for creating configuredRestTemplateinstances in Spring Boot. - Using
BasicAuthenticationInterceptor: A flexible alternative that manually adds authentication behavior to aRestTemplate.
We also covered how to set up the server-side security using the current, component-based Spring Security configuration, which is the standard moving forward. By following these patterns, you can confidently and securely handle service-to-service communication in your Spring ecosystem.