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:
- Go to Settings → Certificates.
- Add:
- Host:
localhost
- CRT file:
client.crt
- KEY file:
client.key
- Host:
- 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."); }