selfsigned
Generate self-signed X.509 certificates using Node.js native crypto.
Install
npm install selfsigned
Requirements
- Node.js >= 15.6.0 (for native WebCrypto support)
Usage
Version 5.0 is async-only. The generate() function now returns a Promise.
const selfsigned = require('selfsigned');
const attrs = [{ name: 'commonName', value: 'contoso.com' }];
const pems = await selfsigned.generate(attrs);
console.log(pems);
Output
{
private: '-----BEGIN PRIVATE KEY-----\n...',
public: '-----BEGIN PUBLIC KEY-----\n...',
cert: '-----BEGIN CERTIFICATE-----\n...',
fingerprint: 'XX:XX:XX:...'
}
Options
const pems = await selfsigned.generate(null, {
keySize: 2048,
notBeforeDate: new Date(),
notAfterDate: new Date('2026-01-01'),
algorithm: 'sha256',
extensions: [{ name: 'basicConstraints', cA: true }],
clientCertificate: true,
clientCertificateCN: 'jdoe',
clientCertificateKeySize: 2048,
ca: { key: '...', cert: '...' }
});
Setting Custom Validity Period
Use notBeforeDate and notAfterDate to control certificate validity:
const { addDays, addYears } = require('date-fns');
const pems = await selfsigned.generate(null, {
notBeforeDate: new Date(),
notAfterDate: addDays(new Date(), 30)
});
const notBefore = new Date();
const notAfter = new Date(notBefore);
notAfter.setFullYear(notAfter.getFullYear() + 2);
const pems = await selfsigned.generate(null, {
notBeforeDate: notBefore,
notAfterDate: notAfter
});
Supported Algorithms
sha1 (default)
sha256
sha384
sha512
Using Your Own Keys
You can avoid key pair generation by specifying your own keys:
const pems = await selfsigned.generate(null, {
keyPair: {
publicKey: '-----BEGIN PUBLIC KEY-----...',
privateKey: '-----BEGIN PRIVATE KEY-----...'
}
});
Signing with a CA
You can generate certificates signed by an existing Certificate Authority instead of self-signed certificates. This is useful for development environments where you want browsers to trust your certificates.
const fs = require('fs');
const selfsigned = require('selfsigned');
const pems = await selfsigned.generate([
{ name: 'commonName', value: 'localhost' }
], {
algorithm: 'sha256',
ca: {
key: fs.readFileSync('/path/to/ca.key', 'utf8'),
cert: fs.readFileSync('/path/to/ca.crt', 'utf8')
}
});
The generated certificate will be signed by the provided CA and will include:
- Subject Alternative Name (SAN) extension with DNS name matching the commonName
- For
localhost, an additional IP SAN for 127.0.0.1
- Key Usage: digitalSignature, keyEncipherment
- Extended Key Usage: serverAuth, clientAuth
Using with mkcert
mkcert is a simple tool for making locally-trusted development certificates. Combining it with selfsigned provides an excellent developer experience:
- No certificate files to manage - generate trusted certificates on-the-fly at server startup
- No git-ignored cert files - nothing to store, share, or accidentally commit
- Browsers trust the certificates automatically - no security warnings during development
const https = require('https');
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const selfsigned = require('selfsigned');
const caroot = execSync('mkcert -CAROOT', { encoding: 'utf8' }).trim();
const pems = await selfsigned.generate([
{ name: 'commonName', value: 'localhost' }
], {
algorithm: 'sha256',
ca: {
key: fs.readFileSync(path.join(caroot, 'rootCA-key.pem'), 'utf8'),
cert: fs.readFileSync(path.join(caroot, 'rootCA.pem'), 'utf8')
}
});
https.createServer({ key: pems.private, cert: pems.cert }, app).listen(443);
See examples/https-server-mkcert.js for a complete working example.
Attributes
Attributes follow the X.509 standard:
const attrs = [
{ name: 'commonName', value: 'example.org' },
{ name: 'countryName', value: 'US' },
{ shortName: 'ST', value: 'Virginia' },
{ name: 'localityName', value: 'Blacksburg' },
{ name: 'organizationName', value: 'Test' },
{ shortName: 'OU', value: 'Test' }
];
Generate Client Certificates
For environments where servers require client certificates, you can generate client keys signed by the original (server) key:
const pems = await selfsigned.generate(null, { clientCertificate: true });
console.log(pems);
Output includes additional client certificate fields:
{
private: '-----BEGIN PRIVATE KEY-----\n...',
public: '-----BEGIN PUBLIC KEY-----\n...',
cert: '-----BEGIN CERTIFICATE-----\n...',
fingerprint: 'XX:XX:XX:...',
clientprivate: '-----BEGIN PRIVATE KEY-----\n...',
clientpublic: '-----BEGIN PUBLIC KEY-----\n...',
clientcert: '-----BEGIN CERTIFICATE-----\n...'
}
To override the default client CN of John Doe jdoe123:
const pems = await selfsigned.generate(null, {
clientCertificate: true,
clientCertificateCN: 'FooBar'
});
PKCS#7 Support
PKCS#7 formatting is available through a separate module for better tree-shaking:
const selfsigned = require('selfsigned');
const { createPkcs7 } = require('selfsigned/pkcs7');
const pems = await selfsigned.generate(attrs);
const pkcs7 = createPkcs7(pems.cert);
console.log(pkcs7);
You can also create PKCS#7 for client certificates:
const pems = await selfsigned.generate(null, { clientCertificate: true });
const clientPkcs7 = createPkcs7(pems.clientcert);
Migration from v4.x
Version 5.0 introduces breaking changes:
Breaking Changes
- Async-only API: The
generate() function is now async and returns a Promise. Synchronous generation is no longer supported.
- No callback support: Callbacks have been removed. Use
async/await or .then().
- Minimum Node.js version: Now requires Node.js >= 15.6.0 (was >= 10).
- Dependencies: Replaced
node-forge with @peculiar/x509 and pkijs (66% smaller bundle size).
days option removed: Use notAfterDate instead. Default validity is 365 days from notBeforeDate.
Migration Examples
Old (v4.x):
const pems = selfsigned.generate(attrs, { days: 365 });
selfsigned.generate(attrs, { days: 365 }, function(err, pems) {
if (err) throw err;
console.log(pems);
});
New (v5.x):
const pems = await selfsigned.generate(attrs);
const notAfter = new Date();
notAfter.setDate(notAfter.getDate() + 30);
const pems = await selfsigned.generate(attrs, { notAfterDate: notAfter });
selfsigned.generate(attrs)
.then(pems => console.log(pems))
.catch(err => console.error(err));
License
MIT