Learnitweb

Implementing Mutual TLS (mTLS) in a Spring Boot Application

Mutual TLS (mTLS) is an extension of TLS where both the client and the server authenticate each other using certificates. This is often used in internal APIs, microservices, or when you want high assurance that only trusted clients can connect to your server.

Step 1: Generate Server and Client Certificates

1.1 Create a Root Certificate Authority (CA)

openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.pem \
  -subj "/C=IN/ST=MH/L=Pune/O=MyOrg/OU=MyTeam/CN=MyRootCA"

1.2 Create a Server Certificate

# Generate key
openssl genrsa -out server.key 2048

# Create CSR
openssl req -new -key server.key -out server.csr \
  -subj "/C=IN/ST=MH/L=Pune/O=MyOrg/OU=MyTeam/CN=localhost"

# Sign with CA
openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial \
  -out server.crt -days 365 -sha256

1.3 Create a Client Certificate

# Generate key
openssl genrsa -out client.key 2048

# Create CSR
openssl req -new -key client.key -out client.csr \
  -subj "/C=IN/ST=MH/L=Pune/O=MyOrg/OU=MyTeam/CN=my-client"

# Sign with CA
openssl x509 -req -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial \
  -out client.crt -days 365 -sha256

Step 2: Create Keystores and Truststores

2.1 Convert Server Certificate and Key to PKCS12

openssl pkcs12 -export -in server.crt -inkey server.key \
  -out server-keystore.p12 -name server \
  -CAfile ca.pem -caname rootCA

2.2 Create Server Truststore (to trust client)

keytool -import -trustcacerts -alias clientca -file ca.pem \
  -keystore server-truststore.jks -storepass changeit -noprompt

2.3 (Optional) Create Client Keystore and Truststore (if testing from Java client)

openssl pkcs12 -export -in client.crt -inkey client.key \
  -out client-keystore.p12 -name client \
  -CAfile ca.pem -caname rootCA

keytool -import -trustcacerts -alias serverca -file ca.pem \
  -keystore client-truststore.jks -storepass changeit -noprompt

Step 3: Configure Spring Boot for mTLS

3.1 Add Properties in application.yml or application.properties

If using application.yml:

server:
  port: 8443
  ssl:
    enabled: true
    key-store: classpath:server-keystore.p12
    key-store-password: changeit
    key-store-type: PKCS12
    key-alias: server
    trust-store: classpath:server-truststore.jks
    trust-store-password: changeit
    trust-store-type: JKS
    client-auth: need

Explanation:

  • client-auth: need → requires client to present certificate.
  • If you want to allow both with/without client certs: use client-auth: want.

3.2 Place the Files in src/main/resources

Copy:

  • server-keystore.p12
  • server-truststore.jks

into:
src/main/resources/

Step 4: Start Spring Boot and Test mTLS

Test with curl:

curl -v https://localhost:8443/api/hello \
  --cert client.crt --key client.key \
  --cacert ca.pem

You should see a valid 200 response. If you remove the --cert and --key, the server should reject the connection.

Test with Postman:

  1. Go to Settings → Certificates.
  2. Add:
    • Host: localhost
    • CRT file: client.crt
    • KEY file: client.key
  3. Send a request to https://localhost:8443/ — it should work.

Optional: Secure Spring Boot Endpoint with Principal Info

You can access client certificate info in controller:

@GetMapping("/secure")
public ResponseEntity<String> secureEndpoint(HttpServletRequest request) {
    X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
    if (certs != null && certs.length > 0) {
        String clientCN = certs[0].getSubjectX500Principal().getName();
        return ResponseEntity.ok("Hello, client: " + clientCN);
    }
    return ResponseEntity.status(HttpStatus.FORBIDDEN).body("No client certificate found.");
}