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.

Java One
Java One
Java One
How to Implement Mutual SSL Authentication in Spring Boot (HTTPS)

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.crt

Import the client certificate into the server’s trust store:

keytool -importcert -file client.crt -alias serverTrustStore -keystore serverTrustStore.jks

2.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: 8443

Configure 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 list

Disabling 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.

Spring BootHTTPSSSLPostmanMutual TLS
Java One
Written by

Java One

Sharing common backend development knowledge.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.