Skip to content
Santekno.com | Tech Tutorials and Trends
EN
📖 0%
03 Aug 2025 · 6 min read ·Article 56 / 110
Go

56. Validating Client Certificates on the Server

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

56. Validating Client Certificates on the Server: An In-Depth Guide with Code Examples and Diagrams

Validating client certificates on the server is a fundamental element of building secure communication systems based on TLS/SSL. Many engineers are familiar with HTTPS and SSL certificates for servers—but quite a few have never implemented client authentication because it is perceived as complex or bureaucratically heavy. In reality, client certificate validation provides a significant additional layer of protection, especially for internal systems, APIs, or service-to-service communication (mTLS). In this article we will thoroughly explore client certificate validation, from the concept and the flow to implementation practices (code examples) and a hands-on simulation, so you can start applying it directly in your own projects.


What Is Client Certificate Validation?

In general, when establishing a TLS connection, the server presents a certificate to the client to prove its identity. However, with mutual TLS (mTLS), the client must also present a certificate to the server. The server then validates the client certificate before granting access.

Validation typically covers:

  • A trusted issuer (CA)
  • The certificate validity period (valid from & valid until)
  • Certificate features/fingerprint (for example, a particular extension)
  • Revocation status (CRL/OCSP)

The direct benefits are:

  • Two-way authentication: Not only is the server verified, but the client is verified as well.
  • Rejecting unauthorized clients: Only clients with a valid certificate can access the server/API.
  • A better fit for machine-to-machine communication: For example, between microservices, IoT gateways, and so on.

Flow Diagram: TLS Handshake with Client Certificate Validation

Before diving into the code, let’s look at the handshake flow using the following mermaid diagram:

MERMAID
sequenceDiagram
    participant Client
    participant Server

    Client->>Server: Client Hello (cipher suite, etc)
    Server->>Client: Server Hello + Certificate
    Server->>Client: (Optional) Certificate Request
    Client->>Server: Client Certificate
    Client->>Server: Key Exchange
    Server->>Client: Server Finished
    Client->>Server: Client Finished

    Note over Server: Validasi Sertifikat Client 
(CA trust, Validity, Revocation)

During the Certificate Request stage, the server asks the client for its certificate. Once received, the server validates it before continuing the handshake.


Applying It in the Real World: Simulation and Code

Let’s run a simple simulation with a web server built on Node.js using the Express framework. Our focus is on:

  1. Preparing the root CA, the server certificate, and the client certificate
  2. Setting up an Express server that validates the client certificate
  3. Simulating client requests using curl

1. Preparing the Certificates (with OpenSSL)

a. Create the root CA

bash
1openssl genrsa -out rootCA.key 2048
2openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem -subj "/CN=RootCA"

b. Create the server certificate

bash
1openssl genrsa -out server.key 2048
2openssl req -new -key server.key -out server.csr -subj "/CN=localhost"
3openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256

c. Create the client certificate

bash
1openssl genrsa -out client.key 2048
2openssl req -new -key client.key -out client.csr -subj "/CN=client"
3openssl x509 -req -in client.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out client.crt -days 500 -sha256

In the end, we’ll have the files: rootCA.pem, server.crt, server.key, client.crt, client.key.


2. Configuring Express with Client Certificate Validation

The simple code below forces the client to send a certificate, and the server will reject any request without a certificate or with an invalid one.

js
 1const fs = require('fs');
 2const https = require('https');
 3const express = require('express');
 4
 5const app = express();
 6
 7// TLS configuration with the CA and client cert validation
 8const options = {
 9  key: fs.readFileSync('server.key'),
10  cert: fs.readFileSync('server.crt'),
11  ca: fs.readFileSync('rootCA.pem'),
12  requestCert: true,         // Require the client to send a certificate
13  rejectUnauthorized: true,  // Reject if invalid/CA is unknown
14};
15
16app.get('/', (req, res) => {
17  // req.client.authorized is automatically true if the certificate is valid & trusted
18  if (req.client.authorized) {
19    res.send('Hello, Client with a valid certificate!');
20  } else {
21    res.status(401).send('Access denied: invalid client certificate');
22  }
23});
24
25https.createServer(options, app).listen(3443, () => {
26  console.log('Server listening at https://localhost:3443');
27});

The Express server above will only accept requests from clients with a valid certificate signed by the same Root CA.


3. Simulating Client Requests

  • Client request with a valid certificate:

bash
1curl -v https://localhost:3443 \
2  --cacert rootCA.pem \
3  --cert client.crt \
4  --key client.key
Server response: Hello, Client with a valid certificate!

  • Client request WITHOUT a certificate:

bash
1curl -v https://localhost:3443 --cacert rootCA.pem
Server response: Access denied: invalid client certificate


Case Study: Client Authorization Scheme Table

Suppose you manage an internal payroll API service. The clients allowed in are a specific list that has each been issued its own certificate. Each certificate is given a Common Name (CN) matching the name of the application/institution:

CNApplicationExpiredAccepted by Server?
payroll-appPayroll System2025-01-01✔️ Yes
finance-appFinance Dashboard2023-12-01❌ No
ext-userExternal Vendor2025-05-20✔️ Yes
unknown-userNot registered2025-06-30❌ No

Further validation can be performed through the SAN (Subject Alternative Name) field or other extensions, for example to manage roles/privileges.


Best Practices for Client Certificate Validation

  1. Use a trusted CA and manage its distribution securely.
    Avoid self-signed CAs for large systems.

  2. Automate certificate rotation & revocation.
    Implement a system to renew/deactivate client certificates that have expired or been revoked.

  3. Maintain structured logging of all handshake activity.
    Including who failed and why.

  4. Verify certificate extensions and attributes according to your organization’s policies.

  5. Use mutual TLS only for critical/internal endpoints,
    because implementing it on the client side adds complexity.


Conclusion

Validating client certificates on the server is a strong security mechanism, especially in machine-to-machine communication scenarios that require two-way authentication. The implementation does require a bit of extra effort (a CA certificate, distributing client certificates, and so on), but the benefits are well worth the level of security you gain.

In the real world, practices such as mutual TLS have already become a best practice across many financial APIs, Open Banking, and service meshes (Istio/Linkerd). Hopefully the article and code examples above help you understand and start applying client certificate validation in your own systems.

Keep up the enthusiasm for tinkering with security features, because defense in depth will save you from a cybersecurity nightmare!


Further references

Related Articles

💬 Comments