Node.js HTTPS Client with Custom SSL/TLS Certificates

This article explains how to configure custom SSL/TLS certificates for making secure HTTPS client requests in Node.js. You will learn how to load custom Certificate Authorities (CA), client certificates, and private keys using the native https module to establish secure, authenticated connections with external servers.

Loading Certificate Files

To configure custom certificates, you must first load the certificate files from your file system. This is typically done using the built-in fs (File System) module. You will need to read these files as buffers or strings.

const fs = require('fs');
const path = require('path');

// Load the custom CA, client certificate, and client private key
const customCA = fs.readFileSync(path.join(__dirname, 'ca.pem'));
const clientCert = fs.readFileSync(path.join(__dirname, 'client-cert.pem'));
const clientKey = fs.readFileSync(path.join(__dirname, 'client-key.pem'));

Configuring the HTTPS Request Options

When making an HTTPS request, Node.js allows you to pass an options object to customize the TLS handshake. You can inject your custom certificates into this object using specific properties:

const options = {
  hostname: 'secure.example.com',
  port: 443,
  path: '/api/data',
  method: 'GET',
  ca: customCA,           // Trust the custom CA
  key: clientKey,         // Client private key for mTLS
  cert: clientCert,       // Client certificate for mTLS
  rejectUnauthorized: true // Enforce certificate validation
};

Making the Secure HTTPS Request

Once the options object is configured, pass it to https.request() or https.get(). The underlying TLS agent will use your custom credentials during the handshake.

const https = require('https');

const req = https.request(options, (res) => {
  console.log(`Status Code: ${res.statusCode}`);

  res.on('data', (chunk) => {
    process.stdout.write(chunk);
  });
});

req.on('error', (err) => {
  console.error(`Secure connection failed: ${err.message}`);
});

// End the request
req.end();

Using a Custom Agent for Reusable Connections

If you need to make multiple requests using the same SSL/TLS configuration, it is highly efficient to create a reusable https.Agent. This avoids the overhead of performing a full TLS handshake for every single request.

const secureAgent = new https.Agent({
  ca: customCA,
  key: clientKey,
  cert: clientCert,
  keepAlive: true
});

// Reuse the agent across multiple request options
const requestOptions = {
  hostname: 'secure.example.com',
  port: 443,
  path: '/api/resource',
  method: 'POST',
  agent: secureAgent
};