This guide shows how to validate mTLS certificate-bound access tokens in an Express API using the MonoCloud Backend Node SDK.
mTLS certificate binding ensures that an access token can only be used by the client that holds the corresponding TLS certificate.
This guide assumes you've completed the installation guide.
You should already have:
@monocloud/backend-node SDK installed.envCreate an HTTPS server with mTLS and certificate binding validation:
import "dotenv/config";
import express, { type Request } from "express";
import https from "https";
import fs from "fs";
import { TLSSocket } from "tls";
import { X509Certificate } from "crypto";
import {
protectApi,
type ClientCertificateResolver,
type AuthenticatedExpressRequest,
} from "@monocloud/backend-node/express";
const app = express();
app.use(express.json());
// Resolve the client certificate from the TLS connection
const certificateResolver: ClientCertificateResolver<Request> = async (req) => {
const { socket } = req;
if (socket instanceof TLSSocket) {
const cert = socket.getPeerCertificate(true);
if (cert && cert.raw) {
return new X509Certificate(cert.raw).toString();
}
}
return "";
};
// Create the middleware with the certificate resolver
const protect = protectApi({ certificateResolver });
// Validate certificate binding on all routes
app.use(protect({ validateCertificateBinding: true }));
app.get("/api/data", (req, res) => {
const { claims } = req as AuthenticatedExpressRequest;
res.json({ claims });
});
// Create the HTTPS server
const server = https.createServer(
{
key: fs.readFileSync("<your-server-key.pem>"),
cert: fs.readFileSync("<your-server-cert.pem>"),
requestCert: true,
rejectUnauthorized: false,
},
app
);
server.listen(3000, () => {
console.log("HTTPS server running on https://localhost:3000");
});
How it works:
requestCert: true tells the server to request a client certificate during the TLS handshakerejectUnauthorized: false allows the application to handle certificate validation instead of rejecting the request at the TLS levelcertificateResolver extracts the PEM-encoded client certificate from the TLS connectionvalidateCertificateBinding: true verifies that the token's cnf.x5t#S256 claim matches the SHA-256 thumbprint of the client certificate| Scenario | Status code | Response |
|---|---|---|
| Missing or invalid token | 401 | { "message": "unauthorized" } |
| Token not bound to a certificate | 401 | { "message": "unauthorized" } |
| Certificate thumbprint mismatch | 401 | { "message": "unauthorized" } |
| Valid token with matching certificate | — | Route handler executes normally |