How to Implement Mutual SSL Authentication in Spring Boot (HTTPS)
This guide explains the difference between one‑way and two‑way SSL/TLS authentication, shows how to generate self‑signed and CA certificates with keytool, configures Spring Boot for mutual authentication, and demonstrates testing the setup using Postman, including detailed steps, code snippets, and troubleshooting tips.
1. One‑Way Authentication
The one‑way SSL/TLS authentication process involves the server presenting its certificate to the client, which validates the certificate against its trusted TrustStore. The server’s public key is stored in a KeyStore containing the private key, public key, and certificate.
Use keytool to create a self‑signed certificate and store it in a KeyStore.
During the handshake, the server sends the public key from the KeyStore to the client.
The client verifies the server’s certificate by checking its TrustStore for the corresponding certificate.
The client encrypts data with the server’s public key; the server decrypts it using its private key from the KeyStore.
1.1 Self‑Signed vs CA Certificates
Self‑signed certificates are trusted only if the client explicitly imports them. CA‑issued certificates are validated through a certificate chain that must link back to a root CA stored in the client’s trust store.
1.2 Limitations of One‑Way Authentication
One‑way authentication only verifies the server; it cannot guarantee the client’s legitimacy. In high‑security environments, such as internal financial systems, mutual authentication is required to ensure that only authorized clients can connect.
2. Two‑Way (Mutual) Authentication
Mutual authentication extends the handshake so that both client and server present certificates and verify each other.
2.1 Certificate Generation and Distribution
Generate a client keystore and export its certificate:
keytool -genkeypair -alias clientKeyStore -keyalg RSA -keysize 4096 -storetype PKCS12 -keystore clientKeyStore.p12 -validity 3650 -storepass password keytool -export -keystore clientKeyStore.p12 -alias serverKeyStore -file client.crtImport the client certificate into the server’s trust store:
keytool -importcert -file client.crt -alias serverTrustStore -keystore serverTrustStore.jks2.2 Spring Boot Configuration
Add the following properties to the server configuration to enable mutual authentication:
server:
ssl:
key-store: classpath:serverKeyStore.p12
key-store-password: password
key-store-type: PKCS12
key-alias: serverKeyStore
key-password: password
client-auth: need
trust-store: classpath:serverTrustStore.jks
trust-store-password: password
trust-store-type: JKS
trust-alias: serverTrustStore
trust-password: password
port: 8443Configure a RestTemplate that loads the client keystore and truststore:
@Slf4j
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory httpComponentsClientHttpRequestFactory) {
RestTemplate restTemplate = new RestTemplate(httpComponentsClientHttpRequestFactory);
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
return restTemplate;
}
@Bean("httpComponentsClientHttpRequestFactory")
public ClientHttpRequestFactory httpComponentsClientHttpRequestFactory() throws IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
final String allPassword = "123456";
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
SSLContext sslContext = SSLContextBuilder
.create()
.loadKeyMaterial(new ClassPathResource("clientKeystore.p12").getURL(), allPassword.toCharArray(), allPassword.toCharArray())
.loadTrustMaterial(new ClassPathResource("clientTruststore.jks").getURL(), allPassword.toCharArray())
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
HttpClient client = HttpClients.custom()
.setSSLContext(sslContext)
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(client);
return requestFactory;
}
}With these settings, the Spring Boot application can both present its certificate and validate the client’s certificate.
3. Testing with Postman
To verify the mutual TLS setup, configure Postman as the client:
Host : the server address (e.g., 127.0.0.1:24443) must match the DNS/IP in the server certificate.
CRT file : the client certificate file (e.g., client.crt).
KEY file : the client private key (generated with keytool + openssl).
PFX file : a combined keystore containing both certificate and private key (e.g., clientKeyStore.p12).
Enable SSL certificate verification in Postman’s Settings. If the server’s certificate is self‑signed, you may need to disable this verification or ensure the certificate is trusted.
If the host/IP does not match the certificate’s subject alternative names, Postman will report an error such as:
Error: Hostname/IP does not match certificate's altnames: IP:127.0 is not in the cert's listDisabling Enable SSL certificate verification bypasses this check, but it is not recommended for production environments.
4. Conclusion
Mutual SSL/TLS authentication is a core feature of Spring Boot for securing private or internal services. While many projects use it implicitly, understanding the certificate generation, keystore configuration, and client testing steps helps avoid common pitfalls and ensures both server and client identities are properly verified.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
