Node.js: check the validity of a website SSL certificate

In this tutorial we will see how to check the validity of a site's SSL certificate using Node.js.

It involves making an HTTPS request of the HEAD type and comparing the expiration date of the certificate obtained from the response object and the successful status of the SSL transaction (handshake) as reported by the underlying socket.

'use strict';

const https = require('https');
const validator = require('validator');


const getDaysBetween = (validFrom, validTo) => {
    return Math.round(Math.abs(+validFrom - +validTo) / 8.64e7);
};

const getDaysRemaining = (validFrom, validTo) => {
    const daysRemaining = getDaysBetween(validFrom, validTo);
    if (new Date(validTo).getTime() < new Date().getTime()) {
        return -daysRemaining;
    }
    return daysRemaining;
};

const getSSLCertificateInfo = host => {
    if(!validator.isFQDN(host)) {
        return Promise.reject(new Error('Invalid host.'));
    }
    const options = {
        agent: false,
        method: 'HEAD',
        port: 443,
        rejectUnauthorized: false,
        hostname: host
    };

    return new Promise((resolve, reject) => {
        try {
            const req = https.request(options, res => {
                const crt = res.connection.getPeerCertificate(),
                    vFrom = crt.valid_from, vTo = crt.valid_to;
                var validTo = new Date(vTo);
                resolve({
                    daysRemaining: getDaysRemaining(new Date(), validTo),
                    valid: res.socket.authorized || false,
                    validFrom: new Date(vFrom).toISOString(),
                    validTo: validTo.toISOString()
                });
            });
            req.on('error', reject);
            req.end();
        } catch (e) {
            reject(e);
        }
    });
};

The properties that interest us most of the object returned by the Promise are daysRemaining and valid. We can use them in the following way:

const checkCertificateValidity = async host => {
            let isValid = true;
        try {
            const res = await getSSLCertificateInfo(this.host);
            if(res.daysRemaining <= 0 || !res.valid) {
                isValid = false;
            }
        } catch(err)  {
            isValid = false;
        }

        return isValid;
};

This solution allows us to avoid having to use SSL utilities from the shell that would force us to pass an arbitrary parameter to commands.

Back to top