{"id":15952,"library":"acme-client","title":"ACME Client for Node.js","description":"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.","status":"active","version":"5.4.0","language":"javascript","source_language":"en","source_url":"https://github.com/publishlab/node-acme-client","tags":["javascript","acme","client","lets","encrypt","acmev2","boulder","typescript"],"install":[{"cmd":"npm install acme-client","lang":"bash","label":"npm"},{"cmd":"yarn add acme-client","lang":"bash","label":"yarn"},{"cmd":"pnpm add acme-client","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Used internally for generating and parsing Certificate Signing Requests (CSRs).","package":"@peculiar/x509","optional":false}],"imports":[{"note":"While CommonJS `require` works for `acme-client`, the destructuring `const { Client } = require('acme-client');` is the idiomatic way for named exports in CJS.","wrong":"const Client = require('acme-client').Client;","symbol":"Client","correct":"import { Client } from 'acme-client';"},{"note":"The `directory` object, containing predefined ACME server URLs (e.g., Let's Encrypt, Buypass), is a named export from the main package, not a default export or a separate submodule.","wrong":"import directory from 'acme-client/directory';","symbol":"directory","correct":"import { directory } from 'acme-client';"},{"note":"For TypeScript users, importing types is crucial for proper type checking and IDE auto-completion. The `Client` class can be aliased for clarity if desired.","symbol":"AcmeClient","correct":"import type { Client as AcmeClient } from 'acme-client';"}],"quickstart":{"code":"import { Client, directory } from 'acme-client';\nimport { createPrivateKey } from 'crypto';\n\nasync function runAcmeClient() {\n    // In a real application, load this from a secure source or generate it once\n    const accountPrivateKey = createPrivateKey({\n        type: 'rsa',\n        modulusLength: 2048,\n        publicKeyEncoding: {\n            type: 'spki',\n            format: 'pem'\n        },\n        privateKeyEncoding: {\n            type: 'pkcs8',\n            format: 'pem'\n        }\n    }).export({ type: 'pkcs8', format: 'pem' }).toString();\n\n    console.log('Using account private key (truncated):', accountPrivateKey.substring(0, 50) + '...');\n\n    const client = new Client({\n        directoryUrl: directory.letsencrypt.staging,\n        accountKey: accountPrivateKey,\n    });\n\n    console.log('ACME client initialized with Let\\'s Encrypt staging directory.');\n\n    // Example: Register a new ACME account or get existing one\n    const account = await client.createAccount({\n        termsOfServiceAgreed: true,\n        contact: ['mailto:test@example.com'],\n    });\n\n    console.log('ACME account registered/fetched:', account);\n\n    const accountUrl = client.getAccountUrl();\n    console.log('Account URL:', accountUrl);\n\n    // In a real scenario, you'd now proceed to create an order, generate a CSR, and fulfill challenges.\n    // This quickstart only covers client initialization and account registration.\n}\n\nrunAcmeClient().catch(console.error);","lang":"typescript","description":"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."},"warnings":[{"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`).","message":"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).","severity":"breaking","affected_versions":">=5.0.0"},{"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.","message":"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.","severity":"breaking","affected_versions":">=5.0.0"},{"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).","message":"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.","severity":"gotcha","affected_versions":">=1.0.0"},{"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.","message":"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.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"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).","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.","error":"ERR_OSSL_EVP_UNSUPPORTED: Unsupported cipher algorithm"},{"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.","cause":"The ACME server rejected a request due to malformed data, often an issue with the request payload, headers, or a cryptographic signature.","error":"Error: Invalid response from ACME server (status: 400, type: urn:ietf:params:acme:error:malformed)"},{"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.","cause":"The ACME server requires explicit agreement to its terms of service before an account can be registered or used.","error":"Error: Account terms of service must be agreed"}],"ecosystem":"npm"}