1. Introduction
Transport Layer Security (TLS) is essential for protecting data exchanged between services. In many enterprise systems, microservices need to communicate securely using HTTPS while validating server certificates. One-Way TLS (also known as Server Authentication) ensures that a Spring Boot client verifies the identity of the server it connects to. This article demonstrates how to configure One-Way TLS using RestTemplate in a Spring Boot application, including keystore setup, SSL context configuration, and code examples.
2. Problem
When a Spring Boot application communicates with another HTTPS service, it typically relies on default JDK trust settings. This becomes an issue when:
- The remote server uses a private certificate authority (CA)
- The certificate is self-signed
- Additional trust anchors are required
Without the correct trust configuration, Spring Boot clients fail with errors such as:
javax.net.ssl.SSLHandshakeException: PKIX path building failed3. Solution
One-Way TLS requires only the client to validate the server certificate. The client does not present its own certificate.
The solution consists of:
- Creating a truststore containing the server certificate or CA certificate
- Configuring Spring Boot to load the truststore
- Building an SSLContext with the truststore
- Registering a custom RestTemplate
- Making secure HTTPS calls with server authentication
4. Implementation
4.1 Extract the Server Certificate
openssl s_client -connect secure-api.example.com:443 -showcerts /dev/null | openssl x509 -outform PEM > server.crt4.2 Create a Truststore
keytool -importcert \
-alias secure-api \
-file server.crt \
-keystore truststore.p12 \
-storetype PKCS12 \
-storepass changeitPlace truststore.p12 inside src/main/resources/ssl.
4.3 application.properties
server.ssl.enabled=false
app.ssl.trust-store=classpath:ssl/truststore.p12
app.ssl.trust-store-password=changeit
app.ssl.trust-store-type=PKCS124.4 SSL Configuration Class
import org.apache.hc.client5.http.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
import java.io.InputStream;
import java.security.KeyStore;
@Configuration
public class OneWayTLSConfig {
@Value("${app.ssl.trust-store}")
private String trustStorePath;
@Value("${app.ssl.trust-store-password}")
private String trustStorePassword;
@Value("${app.ssl.trust-store-type}")
private String trustStoreType;
@Bean
public RestTemplate restTemplate() throws Exception {
SSLContext sslContext = createSSLContext();
SSLConnectionSocketFactory socketFactory =
new SSLConnectionSocketFactory(sslContext);
CloseableHttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(socketFactory)
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(requestFactory);
}
private SSLContext createSSLContext() throws Exception {
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
try (InputStream trustStream =
getClass().getResourceAsStream(trustStorePath.replace("classpath:", ""))) {
trustStore.load(trustStream, trustStorePassword.toCharArray());
}
return SSLContexts.custom()
.loadTrustMaterial(trustStore, null)
.build();
}
}4.5 Example Service Using RestTemplate
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class SecureApiService {
private final RestTemplate restTemplate;
public SecureApiService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getSecureData() {
String url = "https://secure-api.example.com/data";
return restTemplate.getForObject(url, String.class);
}
}5. Conclusion
One-Way TLS is an essential security layer for Spring Boot applications that consume HTTPS services. By configuring a custom truststore and wiring a TLS-enabled RestTemplate, applications can safely authenticate servers using private or self-signed certificates. This approach provides secure, reliable communication across microservices and external APIs without requiring mutual TLS (mTLS).