The most surprising thing about TLS client certificate authentication is that it’s not about proving who you are, but about proving who the server is to you.
Let’s look at how this plays out with mTLS (mutual TLS). Imagine a client application, curl, trying to access a protected service running on api.example.com.
curl --cert client.pem --key client.key --cacert ca.pem https://api.example.com/data
When curl initiates the connection, the server api.example.com presents its certificate. curl verifies this certificate against the ca.pem (the Certificate Authority that issued the server’s certificate). If that check passes, the server has proven its identity to curl. This is standard TLS.
Now, for mTLS, the server api.example.com also requests a certificate from curl. curl then presents its own certificate (client.pem) and its private key (client.key) to the server. The server, in turn, verifies curl’s certificate against its own trust store (which would contain the CA that issued client.pem). If both sides successfully validate each other’s certificates, the connection is established. The client has proven its identity to the server, and the server has proven its identity to the client.
This setup is often used for securing internal microservices, B2B integrations, or any scenario where strong, cryptographically verified identity is paramount, and you don’t want to rely solely on username/password or API keys.
Here’s a simplified breakdown of the handshake:
- Client Hello:
curlsends a "hello" message, indicating TLS version and supported cipher suites. - Server Hello:
api.example.comresponds with its chosen TLS version and cipher suite. It also sends its server certificate. - Server Certificate Verification (Client):
curlchecks if the server certificate is valid and signed by a trusted CA (fromca.pem). - Client Certificate Request (Server):
api.example.comrequests a client certificate. - Client Certificate & Key Exchange:
curlsends its client certificate (client.pem) and its private key (client.key) to the server. - Client Certificate Verification (Server):
api.example.comchecks if the client certificate is valid and signed by a trusted CA. - Key Exchange & Encryption: Both sides use the verified certificates to securely exchange a symmetric session key, which is then used to encrypt all subsequent communication.
The key components you’ll be managing are:
- Certificate Authority (CA): The root of trust. You’ll need a CA to sign both server and client certificates. This can be a public CA, an internal enterprise CA, or even a self-signed CA for development/testing.
- Server Certificate & Key: Issued by the CA, identifying the server (
api.example.com). - Client Certificate & Key: Issued by the CA, identifying the client (
curlor your application).
Consider a common configuration for an Nginx server acting as the mTLS endpoint. The relevant directives in nginx.conf (or a site-specific conf file) might look like this:
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/api.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/api.example.com.key;
# mTLS specific directives
ssl_client_certificate /etc/nginx/ssl/ca.crt; # CA that signed client certs
ssl_verify_client on; # or 'optional' if you want to allow unauthenticated access too
# ... other proxy settings ...
}
Here, ssl_client_certificate points to the CA certificate that Nginx will use to verify incoming client certificates. ssl_verify_client on; enforces that a valid client certificate must be presented for the connection to proceed.
The most counterintuitive part of mTLS is often the management of the trust stores. While the server needs to trust the CA that issued the client certificates, the client also needs to trust the CA that issued the server certificates. This means both parties must have a copy of the appropriate CA certificate in their respective trust stores. A common mistake is to only configure the server-side trust for client certs and forget that the client also needs to validate the server cert.
The next step after successfully setting up mTLS is often integrating it with an authorization layer, where the validated client identity is used to grant or deny access to specific resources.