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, {
keyType: 'rsa',
keySize: 2048,
curve: 'P-256',
notBeforeDate: new Date(),
notAfterDate: new Date('2026-01-01'),
algorithm: 'sha256',
extensions: [{ name: 'basicConstraints', cA: true }],
clientCertificate: true,
ca: { key: '...', cert: '...' },
passphrase: 'secret'
});
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
Custom Extensions
You can customize certificate extensions using the extensions option. This is useful for adding Subject Alternative Names (SANs) with IPv6 addresses, custom key usage, and more.
const pems = await selfsigned.generate(
[{ name: 'commonName', value: 'localhost' }],
{
extensions: [
{
name: 'basicConstraints',
cA: false
},
{
name: 'keyUsage',
digitalSignature: true,
keyEncipherment: true
},
{
name: 'subjectAltName',
altNames: [
{ type: 2, value: 'localhost' },
{ type: 7, ip: '127.0.0.1' },
{ type: 7, ip: '::1' }
]
}
]
}
);
Supported Extensions
basicConstraints
{
name: 'basicConstraints',
cA: true,
pathLenConstraint: 0,
critical: true
}
keyUsage
{
name: 'keyUsage',
digitalSignature: true,
nonRepudiation: true,
keyEncipherment: true,
dataEncipherment: true,
keyAgreement: true,
keyCertSign: true,
cRLSign: true,
encipherOnly: true,
decipherOnly: true,
critical: true
}
extKeyUsage (Extended Key Usage)
{
name: 'extKeyUsage',
serverAuth: true,
clientAuth: true,
codeSigning: true,
emailProtection: true,
timeStamping: true
}
subjectAltName (Subject Alternative Name)
{
name: 'subjectAltName',
altNames: [
{ type: 1, value: 'user@example.com' },
{ type: 2, value: 'example.com' },
{ type: 2, value: '*.example.com' },
{ type: 6, value: 'http://example.com/webid' },
{ type: 7, ip: '127.0.0.1' },
{ type: 7, ip: '::1' }
]
}
Default Extensions
When no extensions option is provided (or an empty array), the following defaults are used:
[
{ name: 'basicConstraints', cA: false, critical: true },
{ name: 'keyUsage', digitalSignature: true, keyEncipherment: true, critical: true },
{ name: 'extKeyUsage', serverAuth: true, clientAuth: true },
{ name: 'subjectAltName', altNames: [
{ type: 2, value: commonName },
]}
]
Elliptic Curve (EC) Keys
By default, selfsigned generates RSA keys. You can generate certificates using elliptic curve cryptography instead, which provides equivalent security with smaller key sizes and faster operations.
const pems = await selfsigned.generate(null, { keyType: 'ec' });
const pems = await selfsigned.generate(null, { keyType: 'ec', curve: 'P-384' });
const pems = await selfsigned.generate(null, {
keyType: 'ec',
curve: 'P-521',
algorithm: 'sha512'
});
Supported curves:
P-256 (default) - 128-bit security, fastest
P-384 - 192-bit security
P-521 - 256-bit security, strongest
EC keys work with all other options including clientCertificate, passphrase, ca, and keyPair:
const pems = await selfsigned.generate(null, {
keyType: 'ec',
passphrase: 'secret'
});
const pems = await selfsigned.generate(null, {
keyType: 'ec',
clientCertificate: true
});
const pems = await selfsigned.generate(null, {
keyType: 'ec',
curve: 'P-256',
keyPair: {
publicKey: existingPublicKey,
privateKey: existingPrivateKey
}
});
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-----...'
}
});
Encrypting the Private Key
You can encrypt the private key with a passphrase using AES-256-CBC:
const pems = await selfsigned.generate(null, {
passphrase: 'my-secret-passphrase'
});
To use the encrypted key, provide the passphrase:
const crypto = require('crypto');
const privateKey = crypto.createPrivateKey({
key: pems.private,
passphrase: 'my-secret-passphrase'
});
const https = require('https');
https.createServer({
key: pems.private,
passphrase: 'my-secret-passphrase',
cert: pems.cert
}, app).listen(443);
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...'
}
Client Certificate Options
The clientCertificate option can be true for defaults, or an options object for full control:
const pems = await selfsigned.generate(null, {
clientCertificate: {
cn: 'jdoe',
keyType: 'rsa',
keySize: 4096,
curve: 'P-256',
algorithm: 'sha256',
notBeforeDate: new Date(),
notAfterDate: new Date('2026-01-01')
}
});
Simple example with just a custom CN:
const pems = await selfsigned.generate(null, {
clientCertificate: { cn: '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