ACME Client for Node.js

raw JSON →
5.4.0 verified Tue Apr 21 auth: no javascript

acme-client is a simple and unopinionated Node.js library designed to interact with ACME (Automatic Certificate Management Environment) APIs, such as those provided by Let's Encrypt, Buypass, Google, and ZeroSSL. It adheres to RFC 8555 for ACME protocol communication. The current stable version is 5.4.0, requiring Node.js >= 16.0.0. The library primarily focuses on certificate management tasks, including account registration, order processing, and challenge fulfillment, supporting both RSA and ECDSA keys through native Node.js cryptography. It differentiates itself by being unopinionated and providing direct control over the ACME workflow, rather than an 'auto-mode' by default (though auto mode is available), and ships with TypeScript types for improved developer experience. While major versions have specific Node.js requirements, the project appears to release updates as needed, rather than on a fixed cadence.

error ERR_OSSL_EVP_UNSUPPORTED: Unsupported cipher algorithm
cause This error typically indicates an incompatibility between Node.js's OpenSSL version and the key or certificate format being processed, often due to deprecated algorithms or features.
fix
Ensure your Node.js version is up-to-date (v16+ is recommended for acme-client v5+). If generating keys, use modern algorithms (e.g., RSA 2048-bit or ECDSA P-256) and standard encodings (PKCS8 for private keys, SPKI for public keys).
error Error: Invalid response from ACME server (status: 400, type: urn:ietf:params:acme:error:malformed)
cause The ACME server rejected a request due to malformed data, often an issue with the request payload, headers, or a cryptographic signature.
fix
Verify that all required fields are present and correctly formatted in your ACME client calls. Check for special characters in contact emails, ensure private keys are valid PEM, and that account/order URLs are correct. Enable debug logging (acme.setLogger) to see the full request and response for more details.
error Error: Account terms of service must be agreed
cause The ACME server requires explicit agreement to its terms of service before an account can be registered or used.
fix
When calling client.createAccount(), ensure you set termsOfServiceAgreed: true. You should only do this after your application (or end-user) has reviewed and accepted the current terms of service.
breaking Version 5.x of `acme-client` requires Node.js version 16 or newer. Older Node.js versions (v10, v8, v4) are compatible with earlier major versions (v4.x, v3.x, v2.x/v1.x respectively).
fix Upgrade your Node.js runtime to version 16 or later, or downgrade `acme-client` to a compatible major version for your Node.js environment (e.g., `npm install acme-client@4`).
breaking Older versions of `acme-client` (pre-v5) might have different API signatures or return types. Always consult the upgrade guide or changelog when moving between major versions.
fix Refer to the `docs/upgrade-v5.md` for specific changes when migrating from `v4.x` to `v5.x`. Check `CHANGELOG.md` for other major version transitions.
gotcha When using external account binding (EAB), ensure that the `kid` and `hmacKey` are correctly provided in the client constructor. Incorrect EAB credentials will lead to account creation or update failures.
fix Double-check the `externalAccountBinding` object for typos and ensure the `kid` and `hmacKey` match those provided by your ACME provider (e.g., ZeroSSL, Google ACME).
gotcha It's critical to store ACME account private keys securely and persist them across application restarts. Losing the account key means losing control over certificates associated with that account.
fix Implement robust key management practices: generate keys once, store them encrypted in a persistent, secure location (e.g., file system, database, KMS), and load them at application startup. Avoid regenerating keys on every run.
npm install acme-client
yarn add acme-client
pnpm add acme-client

Demonstrates how to initialize the ACME client, create a new private key for the ACME account, and register or retrieve an ACME account from the Let's Encrypt staging environment.

import { Client, directory } from 'acme-client';
import { createPrivateKey } from 'crypto';

async function runAcmeClient() {
    // In a real application, load this from a secure source or generate it once
    const accountPrivateKey = createPrivateKey({
        type: 'rsa',
        modulusLength: 2048,
        publicKeyEncoding: {
            type: 'spki',
            format: 'pem'
        },
        privateKeyEncoding: {
            type: 'pkcs8',
            format: 'pem'
        }
    }).export({ type: 'pkcs8', format: 'pem' }).toString();

    console.log('Using account private key (truncated):', accountPrivateKey.substring(0, 50) + '...');

    const client = new Client({
        directoryUrl: directory.letsencrypt.staging,
        accountKey: accountPrivateKey,
    });

    console.log('ACME client initialized with Let\'s Encrypt staging directory.');

    // Example: Register a new ACME account or get existing one
    const account = await client.createAccount({
        termsOfServiceAgreed: true,
        contact: ['mailto:test@example.com'],
    });

    console.log('ACME account registered/fetched:', account);

    const accountUrl = client.getAccountUrl();
    console.log('Account URL:', accountUrl);

    // In a real scenario, you'd now proceed to create an order, generate a CSR, and fulfill challenges.
    // This quickstart only covers client initialization and account registration.
}

runAcmeClient().catch(console.error);