SkillAgentSearch skills...

Selfsigned

Generate self-signed certificates from node.js

Install / Use

/learn @jfromaniello/Selfsigned
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

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', // key type: 'rsa' or 'ec' (default: 'rsa')
  keySize: 2048, // the size for the private key in bits (default: 2048, RSA only)
  curve: 'P-256', // elliptic curve: 'P-256', 'P-384', or 'P-521' (default: 'P-256', EC only)
  notBeforeDate: new Date(), // start of certificate validity (default: now)
  notAfterDate: new Date('2026-01-01'), // end of certificate validity (default: notBeforeDate + 365 days)
  algorithm: 'sha256', // sign the certificate with specified algorithm (default: 'sha1')
  extensions: [{ name: 'basicConstraints', cA: true }], // certificate extensions array
  clientCertificate: true, // generate client cert (default: false) - can also be an options object
  ca: { key: '...', cert: '...' }, // CA key and cert for signing (default: self-signed)
  passphrase: 'secret' // encrypt the private key with a passphrase (default: none)
});

Setting Custom Validity Period

Use notBeforeDate and notAfterDate to control certificate validity:

// Using date-fns
const { addDays, addYears } = require('date-fns');

const pems = await selfsigned.generate(null, {
  notBeforeDate: new Date(),
  notAfterDate: addDays(new Date(), 30) // Valid for 30 days
});

// Or with vanilla JS
const notBefore = new Date();
const notAfter = new Date(notBefore);
notAfter.setFullYear(notAfter.getFullYear() + 2); // Valid for 2 years

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' },     // DNS
          { type: 7, ip: '127.0.0.1' },        // IPv4
          { type: 7, ip: '::1' }               // IPv6
        ]
      }
    ]
  }
);

Supported Extensions

basicConstraints

{
  name: 'basicConstraints',
  cA: true,                    // is this a CA certificate?
  pathLenConstraint: 0,        // max depth of valid cert chain (optional)
  critical: true               // mark as critical extension
}

keyUsage

{
  name: 'keyUsage',
  digitalSignature: true,
  nonRepudiation: true,
  keyEncipherment: true,
  dataEncipherment: true,
  keyAgreement: true,
  keyCertSign: true,          // for CA certificates
  cRLSign: true,              // for CA certificates
  encipherOnly: true,
  decipherOnly: true,
  critical: true
}

extKeyUsage (Extended Key Usage)

{
  name: 'extKeyUsage',
  serverAuth: true,           // TLS server authentication
  clientAuth: true,           // TLS client authentication
  codeSigning: true,
  emailProtection: true,
  timeStamping: true
}

subjectAltName (Subject Alternative Name)

{
  name: 'subjectAltName',
  altNames: [
    { type: 1, value: 'user@example.com' },           // email (rfc822Name)
    { type: 2, value: 'example.com' },                // DNS name
    { type: 2, value: '*.example.com' },              // wildcard DNS
    { type: 6, value: 'http://example.com/webid' },   // URI
    { type: 7, ip: '127.0.0.1' },                     // IPv4 address
    { type: 7, ip: '::1' }                            // IPv6 address
  ]
}

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 },
    // For localhost, also includes: { type: 7, ip: '127.0.0.1' }
  ]}
]

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.

// Generate EC certificate with P-256 curve (default)
const pems = await selfsigned.generate(null, { keyType: 'ec' });

// Generate EC certificate with P-384 curve
const pems = await selfsigned.generate(null, { keyType: 'ec', curve: 'P-384' });

// Generate EC certificate with P-521 curve and SHA-512
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:

// EC certificate with encrypted private key
const pems = await selfsigned.generate(null, {
  keyType: 'ec',
  passphrase: 'secret'
});

// EC certificate with client certificate
const pems = await selfsigned.generate(null, {
  keyType: 'ec',
  clientCertificate: true
});

// Reuse existing EC key pair
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'
});

// The private key will be in encrypted PKCS#8 format:
// -----BEGIN ENCRYPTED PRIVATE KEY-----
// ...
// -----END ENCRYPTED PRIVATE KEY-----

To use the encrypted key, provide the passphrase:

const crypto = require('crypto');

// Decrypt the key
const privateKey = crypto.createPrivateKey({
  key: pems.private,
  passphrase: 'my-secret-passphrase'
});

// Or use directly with HTTPS server
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');

// Get mkcert's CA (requires: brew install mkcert && mkcert -install)
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')
  }
});

// Start server with browser-trusted certificate - no files written to disk
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 ge

Related Skills

View on GitHub
GitHub Stars254
CategoryDevelopment
Updated21d ago
Forks60

Languages

JavaScript

Security Score

95/100

Audited on Mar 3, 2026

No findings