node-acme-client

A simple, unopinionated Node.js client for the ACME protocol, automating certificate issuance from Let's Encrypt and other CAs.

SDK
npm
v5.4.0
295stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
38/100Needs Attention
Development Activity0
Maintenance0
Community72
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture80
Code Quality82
Innovation68
Learning Curve80

acme-client is a Node.js library implementing RFC 8555, the ACME v2 protocol used by Let’s Encrypt, ZeroSSL, Google Trust Services, Buypass, and other certificate authorities to automate domain validation and certificate issuance. It exposes both a low-level AcmeClient class for full control over account registration, order creation, and challenge handling, and a high-level auto() helper that walks through the entire certificate lifecycle from CSR to signed certificate in a single call.

The library ships its own native Node.js crypto module for generating RSA and ECDSA key pairs and CSRs (built on @peculiar/x509), alongside a deprecated node-forge-based interface kept for backward compatibility. It supports http-01, dns-01, and tls-alpn-01 challenge types, external account binding (EAB), and configurable retry/backoff behavior for polling ACME resources, making it suitable for building custom certificate-automation tooling on top of any RFC 8555-compliant CA.

What You Get

  • A low-level AcmeClient class exposing every ACME v2 operation — account creation, order placement, authorization/challenge handling, and certificate finalization.
  • An auto() helper that automates the full issuance flow: CSR parsing, account registration, challenge creation/validation, and certificate download.
  • A native crypto module for generating RSA/ECDSA key pairs and CSRs, plus a legacy node-forge-based interface for backward compatibility.
  • Built-in support for http-01, dns-01, and tls-alpn-01 challenge types with configurable challenge priority.
  • Preconfigured directory URLs for Let’s Encrypt, ZeroSSL, Google Trust Services, and Buypass staging/production endpoints.

Common Use Cases

  • Automated certificate renewal - ops teams script cron jobs that call client.auto() to renew certificates before expiry without manual intervention.
  • Custom ACME tooling - developers building their own certbot-like CLI or Kubernetes cert-manager-style controller use the low-level API for fine-grained control.
  • DNS-01 wildcard issuance - teams issuing wildcard certificates implement challengeCreateFn/challengeRemoveFn hooks against their DNS provider’s API.
  • Multi-CA support - applications that need to switch between Let’s Encrypt, ZeroSSL, or a private ACME server reuse the same client against different directory URLs.

Under The Hood

Architecture The module is organized as a thin layered stack around a single AcmeClient class (src/client.js): an HttpClient (src/http.js) handles JWS-signed request/response plumbing and directory caching, an AcmeApi (src/api.js) maps ACME resource operations onto that HTTP layer, verify.js performs optional internal challenge pre-verification, and auto.js composes all of the above into a single high-level auto() orchestration (register account → parse CSR domains → create order → satisfy challenges → finalize → download certificate). Cross-cutting concerns like key handling live in src/crypto/ (a native interface plus a legacy forge.js shim), keeping protocol logic, HTTP transport, and cryptography cleanly separated; changing the core AcmeClient constructor or HttpClient request signing would ripple through nearly every other module since they all depend on it directly.

Tech Stack The library targets Node.js >= 16 and is written in plain CommonJS JavaScript with hand-maintained TypeScript type definitions (types/*.d.ts) shipped alongside it. It uses axios for HTTP transport, @peculiar/x509 for CSR generation/parsing under the native crypto interface, node-forge for the legacy crypto interface, asn1js for low-level ASN.1 handling, and Node’s built-in debug module for opt-in logging. There is no build step for the runtime code — publishing only generates markdown docs via jsdoc-to-markdown from JSDoc comments in the source.

Code Quality Testing uses Mocha with Chai/chai-as-promised assertions, and — notably — the CI pipeline runs the full test suite against a real local ACME server (Let’s Encrypt’s Pebble plus a Pebble Challenge Test Server and CoreDNS) across multiple Node versions and both EAB-enabled and EAB-disabled configurations, rather than relying solely on mocks. Type definitions are checked with tsd (lint-types), and the codebase is linted with ESLint’s airbnb-base config. Error handling is explicit throughout — HTTP responses are checked for status codes and thrown as descriptive Error objects rather than swallowed, and auto() uses try/catch to distinguish an existing account from a new registration.

What Makes It Unique Unlike most ACME clients that shell out to certbot or wrap a fixed CLI workflow, acme-client is a pure library exposing both a fully composable low-level ACME API and a one-call auto() convenience mode, letting integrators choose their own level of control. Its move to a native Node.js crypto implementation (replacing an OpenSSL-CLI-based approach in early versions, and now offering a .crypto interface built on @peculiar/x509 alongside a deprecated .forge fallback) removes any external binary dependency for key and CSR generation, which is unusual among comparable libraries.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search