### Install node-acme-client Source: https://github.com/publishlab/node-acme-client/blob/master/README.md Install the acme-client package using npm. ```bash $ npm install acme-client ``` -------------------------------- ### Create ACME Client Instance Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Instantiate the AcmeClient with the directory URL and account key. Use this for basic client setup. ```javascript const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.staging, accountKey: 'Private key goes here', }); ``` -------------------------------- ### HTTP-01 Challenge Implementation Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/configuration.md Example of implementing `challengeCreateFn` and `challengeRemoveFn` for the HTTP-01 challenge. This involves writing and removing files from a web server. ```javascript const cert = await client.auto({ csr: certificateRequest, email: 'admin@example.com', termsOfServiceAgreed: true, challengeCreateFn: async (authz, challenge, keyAuthorization) => { const domain = authz.identifier.value; const path = `/.well-known/acme-challenge/${challenge.token}`; // Write to HTTP server await publishToWebServer(domain, path, keyAuthorization); // Wait for propagation await sleep(1000); }, challengeRemoveFn: async (authz, challenge, keyAuthorization) => { const domain = authz.identifier.value; const path = `/.well-known/acme-challenge/${challenge.token}`; // Remove from HTTP server await removeFromWebServer(domain, path); }, }); ``` -------------------------------- ### Configure HTTP Proxy Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/utilities.md Sets up an HTTP proxy for all client requests. Requires the 'acme-client' package to be installed. ```javascript const acme = require('acme-client'); // HTTP proxy acme.axios.defaults.proxy = { protocol: 'http', host: 'proxy.example.com', port: 8080, auth: { username: 'user', password: 'pass' } }; ``` -------------------------------- ### Minimal AcmeClient Configuration Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/configuration.md Use this configuration for basic client setup with production Let's Encrypt directory and an account key. ```javascript const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.production, accountKey: privateKeyBuffer, }); ``` -------------------------------- ### Preferred Chain Configuration Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/configuration.md Example demonstrating how to specify a `preferredChain` when ordering a certificate. This ensures a specific issuer chain, like 'R3', is used if available. ```javascript const cert = await client.auto({ csr: certificateRequest, email: 'admin@example.com', termsOfServiceAgreed: true, challengeCreateFn: async () => { /* ... */ }, challengeRemoveFn: async () => { /* ... */ }, preferredChain: 'R3', // Use R3 chain if available }); ``` -------------------------------- ### Initialize ACME Client Source: https://github.com/publishlab/node-acme-client/blob/master/README.md Initialize the ACME client with a directory URL and account key. This is a common starting point for interacting with ACME servers. ```javascript const acme = require('acme-client'); const accountPrivateKey = ''; const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.staging, accountKey: accountPrivateKey, }); ``` -------------------------------- ### DNS-01 Challenge Implementation Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/configuration.md Example of implementing `challengeCreateFn` and `challengeRemoveFn` for the DNS-01 challenge. This involves creating and deleting TXT records with a DNS provider. The `challengePriority` is set to prefer DNS challenges. ```javascript const cert = await client.auto({ csr: certificateRequest, email: 'admin@example.com', termsOfServiceAgreed: true, challengeCreateFn: async (authz, challenge, keyAuthorization) => { const recordName = `_acme-challenge.${authz.identifier.value}`; // keyAuthorization is already the DNS-01 format await dnsProvider.createTxtRecord(recordName, keyAuthorization); // Wait for DNS propagation (typically 30-60 seconds) await sleep(30000); }, challengeRemoveFn: async (authz, challenge, keyAuthorization) => { const recordName = `_acme-challenge.${authz.identifier.value}`; await dnsProvider.deleteTxtRecord(recordName); }, challengePriority: ['dns-01'], // Prefer DNS for wildcard support }); ``` -------------------------------- ### AcmeClient Configuration with EAB (ZeroSSL Example) Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/configuration.md Set up the client with External Account Binding (EAB) for providers like ZeroSSL, requiring a Key Identifier (kid) and HMAC key. ```javascript const client = new acme.Client({ directoryUrl: acme.directory.zerossl.production, accountKey: privateKeyBuffer, externalAccountBinding: { kid: 'my-eab-key-id', hmacKey: 'my-eab-hmac-secret', }, }); ``` -------------------------------- ### Formatted ACME Error Message Example Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/utilities.md Shows an example of a formatted error message derived from an ACME response, prioritizing the 'detail' field and including the HTTP status. ```text Error: urn:acme:error:rateLimited: Too many requests in the last hour ``` -------------------------------- ### Certificate Expiration Check Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/types.md An example demonstrating how to use the certificate info object to check if a certificate has expired. This is useful for proactive certificate management. ```javascript const info = crypto.readCertificateInfo(cert); if (info.notAfter < new Date()) { console.log('Certificate is expired'); } ``` -------------------------------- ### Get Account URL Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/client.md Retrieve the current account URL. This is useful after account creation or if it was pre-specified during initialization. Throws an error if no account URL exists. ```javascript try { const accountUrl = client.getAccountUrl(); console.log(`Account: ${accountUrl}`); } catch (e) { console.log('Account does not exist yet'); } ``` -------------------------------- ### Get Public Key from Private Key Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Derive the public key from a PEM-encoded private key. ```javascript const { crypto } = require('acme-client'); crypto.getPublicKey(keyPem) ``` -------------------------------- ### Get Challenge Key Authorization (JavaScript) Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/client.md Compute the key authorization value for a challenge. This is domain validation proof material. Use this to generate the required proof for http-01 or dns-01 challenges. ```javascript async getChallengeKeyAuthorization(challenge) ``` ```javascript const challenge = authz.challenges[0]; // http-01 challenge const keyAuth = await client.getChallengeKeyAuthorization(challenge); // For http-01, publish to: /.well-known/acme-challenge/{token} // For dns-01, publish to DNS TXT: _acme-challenge.example.com console.log(`Key authorization: ${keyAuth}`); ``` -------------------------------- ### AcmeClient Configuration with Custom Backoff Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/configuration.md Customize retry attempts and backoff delays for network requests. This example increases retries and adjusts minimum and maximum wait times. ```javascript const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.staging, accountKey: privateKeyBuffer, backoffAttempts: 20, // More retries backoffMin: 2000, // Faster initial retry backoffMax: 60000, // Longer maximum wait }); ``` -------------------------------- ### HTTP-01 Challenge Verification Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/utilities.md Verifies the key authorization is accessible via HTTP GET. The response must be plaintext, with an HTTP 200 status code and no trailing whitespace. ```http GET http://{domain}:80/.well-known/acme-challenge/{token} ``` -------------------------------- ### Get Terms of Service URL Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/client.md Retrieve the CA's Terms of Service URL. Returns null if not provided. Throws an error on network failure. ```javascript const tosUrl = await client.getTermsOfServiceUrl(); if (tosUrl) { console.log(`Please read: ${tosUrl}`); } ``` -------------------------------- ### Verify Challenge (JavaScript) Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/client.md Verify that a challenge is satisfied before notifying the ACME provider. This is the internal verification step (http-01 GET, dns-01 DNS lookup, etc.). Ensure the challenge proof has been published before calling this. ```javascript async verifyChallenge(authz, challenge) ``` ```javascript const keyAuth = await client.getChallengeKeyAuthorization(challenge); // (publish keyAuth to satisfy challenge) await client.verifyChallenge(authz, challenge); console.log('Challenge verified'); ``` -------------------------------- ### Get ACME Order Status Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/client.md Refresh an existing order to get its current status from the ACME provider. Ensure the order object includes the 'url' property obtained from a previous order creation. ```javascript const order = { url: 'https://acme.example.com/acme/order/123' }; const updated = await client.getOrder(order); console.log(`Status: ${updated.status}`); // pending, processing, valid, or invalid ``` -------------------------------- ### Get JWK from Private Key Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Convert a PEM-encoded private key into JWK format. ```javascript const { crypto } = require('acme-client'); crypto.getJwk(keyPem) ``` -------------------------------- ### Get Order Details Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Refresh and retrieve the current state of an order object from the ACME server. ```js const order = { ... }; // Previously created order object const result = await client.getOrder(order); ``` -------------------------------- ### Convenience Method Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/STRUCTURE.txt A single method to automate the entire certificate ordering process. ```APIDOC ## auto(opts) ### Description Completes the certificate ordering process in a single call, handling all necessary steps. ### Method `auto(opts)` ### Parameters #### Request Body - **opts** (object) - Required - Options for the auto-ordering process, including CSR, email, and challenge callbacks. ``` -------------------------------- ### Update Existing Account Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Update an existing ACME account, for example, to change contact information. The contact should be an array of strings. ```js const account = await client.updateAccount({ contact: ['mailto:foo@example.com'], }); ``` -------------------------------- ### Get Authorizations for Order Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Retrieve the authorizations associated with a specific order. This is useful for checking the status of domain validation challenges. ```js const order = { ... }; // Previously created order object const authorizations = await client.getAuthorizations(order); authorizations.forEach((authz) => { const { challenges } = authz; }); ``` -------------------------------- ### Create ACME Client Instance with Options Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Instantiate the AcmeClient with extended options including account URL and backoff settings. Useful for fine-tuning retry behavior and account management. ```javascript const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.staging, accountKey: 'Private key goes here', accountUrl: 'Optional account URL goes here', backoffAttempts: 10, backoffMin: 5000, backoffMax: 30000, }); ``` -------------------------------- ### Client Class Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md The main `Client` class is used to interact with ACME servers. It requires an options object during instantiation, which includes the directory URL and the account key. ```APIDOC ## Client Class ### Description Instantiates the ACME client. ### Constructor `new Client(opts)` ### Parameters #### Options (`opts`) - **directoryUrl** (string) - Required - The URL of the ACME directory. - **accountKey** (Buffer | string) - Required - The account private key. ### Request Example ```javascript const { Client } = require('acme-client'); const client = new Client({ directoryUrl: 'https://example.com/acme/directory', accountKey: fs.readFileSync('account-key.pem') }); ``` ``` -------------------------------- ### Migrate createPublicKey to getPublicKey Source: https://github.com/publishlab/node-acme-client/blob/master/docs/upgrade-v5.md The `createPublicKey` method has been renamed to `getPublicKey` and no longer returns a promise. This change is non-breaking if `await` is used. ```javascript // Before const publicKey = await acme.forge.createPublicKey(privateKey); // After const publicKey = acme.crypto.getPublicKey(privateKey); ``` -------------------------------- ### Get Base64 URL Encoded PEM Body Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Extract and encode the body of a PEM-formatted string using Base64 URL encoding. ```javascript const { crypto } = require('acme-client'); crypto.getPemBodyAsB64u(pem) ``` -------------------------------- ### Get Certificate from ACME Order Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Retrieves the certificate from a previously created ACME order. Optionally, a preferred certificate chain can be specified. ```javascript const order = { ... }; // Previously created order const certificate = await client.getCertificate(order); ``` ```javascript const order = { ... }; // Previously created order const certificate = await client.getCertificate(order, 'DST Root CA X3'); ``` -------------------------------- ### Basic Certificate Ordering Workflow Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md This snippet demonstrates the core workflow for obtaining a certificate using the acme-client. It covers client initialization, CSR creation, and the automated process for handling ACME challenges. ```javascript const acme = require('acme-client'); // Create client const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.production, accountKey: fs.readFileSync('account-key.pem'), }); // Create CSR const [certKey, csr] = await acme.crypto.createCsr({ altNames: ['example.com', 'www.example.com'], }); // Order certificate const cert = await client.auto({ csr, email: 'admin@example.com', termsOfServiceAgreed: true, challengeCreateFn: async (authz, challenge, keyAuth) => { // Satisfy challenge (HTTP, DNS, or TLS-ALPN) }, challengeRemoveFn: async (authz, challenge, keyAuth) => { // Clean up challenge }, }); console.log(cert); // PEM encoded certificate ``` -------------------------------- ### AcmeClient Constructor Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Initializes a new instance of the AcmeClient. It requires the ACME directory URL and the account's private key. Optional parameters include the account URL, external account binding details, and backoff configuration for retries. ```APIDOC ## new AcmeClient(opts) ### Description Initializes a new instance of the AcmeClient. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None #### `opts` (object) - Required Configuration options for the client. - **`opts.directoryUrl`** (string) - Required - The URL of the ACME directory. - **`opts.accountKey`** (buffer | string) - Required - The PEM-encoded account private key. - **`opts.accountUrl`** (string) - Optional - The URL of the ACME account. Defaults to `null`. - **`opts.externalAccountBinding`** (object) - Optional - Configuration for external account binding. - **`opts.externalAccountBinding.kid`** (string) - Required if `externalAccountBinding` is provided - The External Account Binding KID. - **`opts.externalAccountBinding.hmacKey`** (string) - Required if `externalAccountBinding` is provided - The External Account Binding HMAC key. - **`opts.backoffAttempts`** (number) - Optional - Maximum number of backoff attempts for retries. Defaults to `10`. - **`opts.backoffMin`** (number) - Optional - Minimum delay in milliseconds for backoff attempts. Defaults to `5000`. - **`opts.backoffMax`** (number) - Optional - Maximum delay in milliseconds for backoff attempts. Defaults to `30000`. ### Request Example ```js const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.staging, accountKey: 'Private key goes here', }); ``` ### Request Example with Options ```js const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.staging, accountKey: 'Private key goes here', accountUrl: 'Optional account URL goes here', backoffAttempts: 10, backoffMin: 5000, backoffMax: 30000, }); ``` ### Request Example with External Account Binding ```js const client = new acme.Client({ directoryUrl: 'https://acme-provider.example.com/directory-url', accountKey: 'Private key goes here', externalAccountBinding: { kid: 'YOUR-EAB-KID', hmacKey: 'YOUR-EAB-HMAC-KEY', }, }); ``` ``` -------------------------------- ### Importing the acme-client Library Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/utilities.md This snippet shows the standard way to import the acme-client library. Note that utility functions are not directly exported and should be accessed via client methods. ```javascript const acme = require('acme-client'); // Utilities are not directly exported; use client methods instead ``` -------------------------------- ### Get Terms of Service URL Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Retrieve the Terms of Service URL from the ACME server. Check if the CA provides a ToS URL before proceeding. ```javascript const termsOfService = client.getTermsOfServiceUrl(); if (!termsOfService) { // CA did not provide Terms of Service } ``` -------------------------------- ### Client Constructor Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/client.md Initializes a new AcmeClient instance. This is the primary interface for interacting with ACME providers. ```APIDOC ## new Client(opts) ### Description Initializes a new AcmeClient instance, which serves as the main interface for ACME operations. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None #### `opts` Object - **opts.directoryUrl** (string) - Required - The ACME directory URL (e.g., `https://acme-v02.api.letsencrypt.org/directory`). - **opts.accountKey** (buffer or string) - Required - PEM encoded private key for account authentication. - **opts.accountUrl** (string) - Optional - Pre-existing account URL to bypass account creation lookup. - **opts.externalAccountBinding** (object) - Optional - External account binding configuration. - **opts.externalAccountBinding.kid** (string) - Optional - EAB Key Identifier. - **opts.externalAccountBinding.hmacKey** (string) - Optional - EAB HMAC key (for HMAC-SHA256). - **opts.backoffAttempts** (number) - Optional - Maximum retry attempts with exponential backoff (default: 10). - **opts.backoffMin** (number) - Optional - Minimum backoff delay in milliseconds (default: 5000). - **opts.backoffMax** (number) - Optional - Maximum backoff delay in milliseconds (default: 30000). ### Returns AcmeClient instance ### Example ```javascript const acme = require('acme-client'); const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.staging, accountKey: Buffer.from(privateKeyPem), }); ``` ### Example with EAB ```javascript const client = new acme.Client({ directoryUrl: 'https://acme-provider.example.com/directory', accountKey: privateKeyPem, externalAccountBinding: { kid: 'my-eab-kid', hmacKey: 'my-eab-hmac-key', }, }); ``` ``` -------------------------------- ### Basic Client.auto() Usage Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/configuration.md This is the most basic usage of the `client.auto()` method. It requires a CSR and agreement to terms of service. ```javascript const cert = await client.auto(opts); ``` -------------------------------- ### Utilities Methods Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/STRUCTURE.txt Utility functions for configuring logging and the HTTP client. ```APIDOC ## setLogger(fn) ### Description Sets a custom logging function for the client. ### Method `setLogger(fn)` ### Parameters #### Path Parameters - **fn** (function) - Required - The custom logger function. ## axios.defaults ### Description Provides access to the underlying Axios HTTP client's default configuration for customization (e.g., setting up proxies). ### Method `axios.defaults` ### Endpoint N/A (Configuration object) ``` -------------------------------- ### Provide challengeCreateFn for Auto Mode Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/errors.md When using `client.auto()`, you must provide a `challengeCreateFn` callback to handle challenge creation. This function is called by the client to initiate the challenge process. ```javascript await client.auto({ csr, challengeCreateFn: async (authz, challenge, keyAuth) => { // Implementation required }, challengeRemoveFn: async (authz, challenge, keyAuth) => { // Implementation required }, }); ``` -------------------------------- ### auto(opts) Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/client.md Automates certificate ordering by handling account creation, order placement, all challenges, and certificate download in a single call. It requires a CSR, and optionally accepts email, terms of service agreement, challenge handling functions, and other configuration options. ```APIDOC ## auto(opts) ### Description Automates certificate ordering. Handles account creation, order placement, all challenges, and certificate download in one call. ### Method `auto(opts)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body This method does not use a request body in the traditional sense. Parameters are passed via the `opts` object. - **opts.csr** (buffer | string) - Required - PEM encoded Certificate Signing Request - **opts.email** (string) - Optional - Account contact email (will prepend `mailto:`) - **opts.termsOfServiceAgreed** (boolean) - Optional - Must be true to create account. Defaults to `false`. - **opts.challengeCreateFn** (function) - Required - Callback to satisfy challenge - **opts.challengeRemoveFn** (function) - Required - Callback to remove challenge - **opts.skipChallengeVerification** (boolean) - Optional - Skip internal verification before notifying CA. Defaults to `false`. - **opts.challengePriority** (string[]) - Optional - Challenge type priority. Defaults to `['http-01', 'dns-01']`. - **opts.preferredChain** (string) - Optional - Preferred certificate issuer. Defaults to `null`. ### Request Example ```javascript const [key, csr] = await acme.crypto.createCsr({ altNames: ['example.com', 'www.example.com'], }); const cert = await client.auto({ csr, email: 'admin@example.com', termsOfServiceAgreed: true, challengeCreateFn: async (authz, challenge, keyAuth) => { // Write keyAuth to HTTP server or DNS await publishChallenge(authz.identifier.value, keyAuth); }, challengeRemoveFn: async (authz, challenge, keyAuth) => { // Clean up challenge await removeChallenge(authz.identifier.value); }, }); console.log('Certificate obtained'); ``` ### Response #### Success Response - **Promise** - PEM encoded certificate #### Response Example (The response is the PEM encoded certificate string itself, not a JSON object. Example output would be a string starting with '-----BEGIN CERTIFICATE-----'.) ### Error Handling Throws an Error if any step fails. ``` -------------------------------- ### Get Modulus from Cryptographic Input Source: https://github.com/publishlab/node-acme-client/blob/master/docs/forge.md Extracts the modulus from a PEM-encoded private key, certificate, or CSR. Use this to obtain the modulus value for cryptographic operations. ```javascript const m1 = await acme.forge.getModulus(privateKey); const m2 = await acme.forge.getModulus(certificate); const m3 = await acme.forge.getModulus(certificateRequest); ``` -------------------------------- ### Auto Mode Client Configuration Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/types.md Configure the `Client.auto()` method with these options. It includes settings for CSR, account email, terms agreement, challenge handling functions, verification skipping, challenge priority, and preferred certificate chain. ```javascript { csr: Buffer | string, // PEM encoded CSR email: string, // Account contact (optional) termsOfServiceAgreed: boolean, // Must agree to proceed challengeCreateFn: async (authz, challenge, keyAuthorization) => {}, challengeRemoveFn: async (authz, challenge, keyAuthorization) => {}, skipChallengeVerification: boolean, // Skip internal verification challengePriority: string[], // Order of preference: ['http-01', 'dns-01'] preferredChain: string // Issuer CN for chain selection } ``` -------------------------------- ### Get Public Exponent from Cryptographic Input Source: https://github.com/publishlab/node-acme-client/blob/master/docs/forge.md Retrieves the public exponent from a PEM-encoded private key, certificate, or CSR. This is useful for operations requiring the public exponent. ```javascript const e1 = await acme.forge.getPublicExponent(privateKey); const e2 = await acme.forge.getPublicExponent(certificate); const e3 = await acme.forge.getPublicExponent(certificateRequest); ``` -------------------------------- ### Get ACME Client Account URL Source: https://github.com/publishlab/node-acme-client/blob/master/README.md Retrieve the current account URL associated with the ACME client. This can be called after account creation or if the URL was provided during initialization. ```javascript const myAccountUrl = client.getAccountUrl(); ``` -------------------------------- ### Utilities Reference Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/INDEX.md Documents utility functions for HTTP client configuration, logging, challenge verification, directory caching, and error handling. ```APIDOC ## Utilities Reference ### Description This section covers various utility functions and configurations for the ACME client, including HTTP client settings, logging, challenge verification helpers, and resource management. ### Utilities - **HTTP Client Configuration**: ACME settings, proxy configuration, custom headers. - **Logging**: `setLogger()` function for custom logging. - **Challenge Verification**: Details for http-01, dns-01, and tls-alpn-01 challenges. - **Resource Management**: Directory caching, resource URLs, link header parsing. - **Error Handling**: Retry and backoff mechanisms, status code handling, error message formatting. - **Other Utilities**: Certificate chain selection, DNS resolution, JWS/nonce management, PEM/ASN.1 utilities. ### Example Usage ```javascript // Example of setting a custom logger const logger = { info: console.log, warn: console.warn, error: console.error }; acmeClient.setLogger(logger); console.log('Custom logger set.'); ``` ``` -------------------------------- ### Handle ACME API Errors Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/types.md Example of how to catch and log ACME API errors. The error message typically includes the 'detail' field from the ACME error response. ```javascript try { await client.createAccount({ termsOfServiceAgreed: false }); } catch (e) { // Error message includes ACME error detail console.log(e.message); } ``` -------------------------------- ### createOrder Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/client.md Places a new certificate order with the ACME provider. It requires an array of identifier objects, each specifying a type (e.g., 'dns') and a value (e.g., 'example.com'). ```APIDOC ## createOrder(data) ### Description Place a new certificate order with the ACME provider. ### Method POST ### Endpoint /acme/order ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **data** (object) - Required - Order data - **identifiers** (object[]) - Required - Array of identifier objects with `{type: 'dns', value: 'example.com'}` ### Request Example ```json { "identifiers": [ { "type": "dns", "value": "example.com" }, { "type": "dns", "value": "www.example.com" } ] } ``` ### Response #### Success Response (200) - **url** (string) - The URL of the created order. - **authorizations** (array) - An array of authorization objects. - **status** (string) - The current status of the order. #### Response Example ```json { "url": "https://acme.example.com/acme/order/123", "authorizations": [...], "status": "pending" } ``` ### Errors - Throws Error if CA does not return order location header ``` -------------------------------- ### Automated Certificate Ordering Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/client.md Use the `auto` function for a one-stop solution to create accounts, place orders, handle challenges, and download certificates. Ensure you provide valid CSR, email, agreement to terms, and challenge handling functions. ```javascript const [key, csr] = await acme.crypto.createCsr({ altNames: ['example.com', 'www.example.com'], }); const cert = await client.auto({ csr, email: 'admin@example.com', termsOfServiceAgreed: true, challengeCreateFn: async (authz, challenge, keyAuth) => { // Write keyAuth to HTTP server or DNS await publishChallenge(authz.identifier.value, keyAuth); }, challengeRemoveFn: async (authz, challenge, keyAuth) => { // Clean up challenge await removeChallenge(authz.identifier.value); }, }); console.log('Certificate obtained'); ``` -------------------------------- ### Access Let's Encrypt Directory URLs Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Access predefined directory URLs for Let's Encrypt staging and production environments. ```javascript const { directory } = require('acme-client'); directory.letsencrypt.staging directory.letsencrypt.production ``` -------------------------------- ### Get PEM Body as Base64URL Source: https://github.com/publishlab/node-acme-client/blob/master/docs/crypto.md Parses the body of a PEM encoded object and returns it as a Base64URL string. If multiple objects are chained, only the body of the first object is returned. ```javascript const b64uBody = acme.crypto.getPemBodyAsB64u(pem); ``` -------------------------------- ### Store Certificate and Key Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Saves the obtained certificate and its corresponding private key to PEM files. ```javascript fs.writeFileSync('cert.pem', cert); fs.writeFileSync('key.pem', certKey); ``` -------------------------------- ### Get Public Key from PEM Source: https://github.com/publishlab/node-acme-client/blob/master/docs/crypto.md Derive a public key from a PEM encoded private or public key. Use this when you need to extract the public part of a key pair. ```javascript const publicKey = acme.crypto.getPublicKey(privateKey); ``` -------------------------------- ### Create CSR with Basic Options Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/crypto.md Generates a CSR with alternative domain names. A new private key is automatically generated. ```javascript const [key, csr] = await crypto.createCsr({ altNames: ['example.com', 'www.example.com'], }); ``` -------------------------------- ### verifyChallenge(authz, challenge) Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/client.md Verifies that an ACME challenge has been satisfied before notifying the ACME provider. This includes internal verification steps like http-01 GET requests or DNS lookups. ```APIDOC ## verifyChallenge(authz, challenge) ### Description Verify that a challenge is satisfied before notifying the ACME provider. This is the internal verification step (http-01 GET, dns-01 DNS lookup, etc.). ### Method `async verifyChallenge(authz, challenge)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters #### authz (object) - Required - Authorization object - **authz.url** (string) - Required - Authorization URL (for logging) #### challenge (object) - Required - Challenge object - **challenge.url** (string) - Required - Challenge URL - **challenge.type** (string) - Required - Challenge type ### Request Example ```javascript const keyAuth = await client.getChallengeKeyAuthorization(challenge); // (publish keyAuth to satisfy challenge) await client.verifyChallenge(authz, challenge); console.log('Challenge verified'); ``` ### Response #### Success Response (200) - **Promise** — Resolves when challenge is verified #### Response Example None provided. ### Error Handling - Error if challenge cannot be verified - Error on network failure - Error on unknown challenge type ``` -------------------------------- ### Initialize ACME Client with Specific Account URL Source: https://github.com/publishlab/node-acme-client/blob/master/README.md Initialize the ACME client by manually specifying the account URL. This is useful when account creation is prohibited or requires a pre-existing account. ```javascript const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.staging, accountKey: accountPrivateKey, accountUrl: 'https://acme-v02.api.letsencrypt.org/acme/acct/12345678', }); ``` -------------------------------- ### Get Current Account URL Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Retrieve the URL of the currently configured ACME account. Throws an error if no account URL is found, indicating that an account needs to be created first. ```javascript try { const accountUrl = client.getAccountUrl(); } catch (e) { // No account URL exists, need to create account first } ``` -------------------------------- ### Utilities Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Provides utility functions for setting a logger and accessing HTTP client configuration. ```APIDOC ## Utilities ### Description Provides utility functions for logging and HTTP client configuration. ### Methods - **`acme.setLogger(fn)`**: Sets a custom logger function. - **`acme.axios.defaults`**: Provides access to the underlying Axios HTTP client defaults for customization. ### Usage Example ```javascript const acme = require('acme-client'); // Set a custom logger acme.setLogger(console.log); // Customize HTTP client defaults acme.axios.defaults.timeout = 5000; ``` ``` -------------------------------- ### Create New Order Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Create a new order for a certificate. Specify the domain identifiers for which the certificate is requested. ```js const order = await client.createOrder({ identifiers: [ { type: 'dns', value: 'example.com' }, { type: 'dns', value: 'test.example.com' }, ], }); ``` -------------------------------- ### Get JWK from PEM Source: https://github.com/publishlab/node-acme-client/blob/master/docs/crypto.md Convert a PEM encoded private or public key into a JSON Web Key (JWK) object. This is useful for interoperability with systems that use JWK format. ```javascript const jwk = acme.crypto.getJwk(privateKey); ``` -------------------------------- ### Create ALPN Certificate Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Create an ALPN certificate using authorization, key authorization, and a private key. ```javascript const { crypto } = require('acme-client'); await crypto.createAlpnCertificate(authz, keyAuth, keyPem) ``` -------------------------------- ### Configure HTTP Client Proxy Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Set up a proxy for the underlying axios HTTP client. This is necessary if your network requires a proxy to access external services. ```javascript const acme = require('acme-client'); // Configure proxy acme.axios.defaults.proxy = { host: 'proxy.example.com', port: 8080, }; ``` -------------------------------- ### Get Challenge Key Authorization Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Retrieves the key authorization for an ACME challenge. The challenge object should be from a previously resolved identifier authorization. The key obtained needs to be written to satisfy the challenge. ```javascript const challenge = { ... }; // Challenge from previously resolved identifier authorization const key = await client.getChallengeKeyAuthorization(challenge); // Write key somewhere to satisfy challenge ``` -------------------------------- ### AcmeClient Configuration with Pre-existing Account Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/configuration.md Configure the client with a pre-existing account URL to skip the account lookup process. ```javascript const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.production, accountKey: privateKeyBuffer, accountUrl: 'https://acme-v02.api.letsencrypt.org/acme/acct/12345678', }); ``` -------------------------------- ### Retrieve Authorizations for an Order Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/client.md Use this method to get all identifier authorizations for a given order. Each authorization corresponds to a domain within the order. The order object must contain an array of authorization URLs. ```javascript async getAuthorizations(order) ``` ```javascript const authorizations = await client.getAuthorizations(order); authorizations.forEach((authz) => { console.log(`Domain: ${authz.identifier.value}`); console.log(`Status: ${authz.status}`); authz.challenges.forEach((ch) => { console.log(` - ${ch.type}: ${ch.token}`); }); }); ``` -------------------------------- ### Import ACME Crypto Module Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/crypto.md Import the necessary 'acme-client' module and destructure the 'crypto' object for use. ```javascript const acme = require('acme-client'); const { crypto } = acme; ``` -------------------------------- ### Fix: Check Order Status Before Download Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/errors.md Use when `getCertificate()` is called with an order status other than `ready` or `valid`. Check the order status and wait for a `valid` status if necessary before attempting to download the certificate. ```javascript if (order.status !== 'valid') { // Wait for valid status order = await client.waitForValidStatus(order); } ``` -------------------------------- ### Access ZeroSSL Production Directory URL Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Access the predefined directory URL for ZeroSSL production environment. ```javascript const { directory } = require('acme-client'); directory.zerossl.production ``` -------------------------------- ### Fix: Get Order with Valid Order URL Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/errors.md If `getOrder()` is called with an order object missing the `url` property, it means the order object is invalid or incomplete. Ensure the order object obtained from `createOrder()` has a valid `.url` property before calling `getOrder()` again. ```javascript const order = await client.createOrder(identifiers); // Order now has .url property const updated = await client.getOrder(order); ``` -------------------------------- ### Fix: Update DNS TXT Record for DNS-01 Challenge Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/errors.md For the DNS-01 challenge, ensure the TXT record is correctly updated with the key authorization before the challenge is completed. Allow sufficient time for DNS propagation. ```javascript // Ensure DNS TXT record is updated before challenge completion const recordName = `_acme-challenge.example.com`; const keyAuth = await client.getChallengeKeyAuthorization(challenge); // For DNS-01, keyAuth is already base64url(SHA256(...)) await dnsProvider.createTxtRecord(recordName, keyAuth); // Wait for propagation (30-60 seconds typical) await sleep(30000); ``` -------------------------------- ### Certificate Ordering Methods Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/STRUCTURE.txt Methods for ordering, retrieving, finalizing, and revoking certificates. ```APIDOC ## createOrder(data) ### Description Places a new certificate order with the ACME server. ### Method `createOrder(data)` ### Parameters #### Request Body - **data** (object) - Required - Order details, including the CSR. ## getOrder(order) ### Description Retrieves the status of an existing certificate order. ### Method `getOrder(order)` ### Parameters #### Path Parameters - **order** (string) - Required - The order identifier. ## finalizeOrder(order, csr) ### Description Submits the Certificate Signing Request (CSR) to finalize the order. ### Method `finalizeOrder(order, csr)` ### Parameters #### Path Parameters - **order** (string) - Required - The order identifier. - **csr** (string) - Required - The Certificate Signing Request in PEM format. ## getCertificate(order, preferredChain) ### Description Downloads the issued certificate for a given order. ### Method `getCertificate(order, preferredChain)` ### Parameters #### Path Parameters - **order** (string) - Required - The order identifier. - **preferredChain** (string) - Optional - The preferred certificate chain. ## revokeCertificate(cert, data) ### Description Revokes a previously issued certificate. ### Method `revokeCertificate(cert, data)` ### Parameters #### Path Parameters - **cert** (string) - Required - The certificate to revoke. #### Request Body - **data** (object) - Required - Data related to the revocation. ``` -------------------------------- ### Create ACME Client with External Account Binding Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Instantiate the AcmeClient with external account binding (EAB) details. Required when using EAB for account authentication. ```javascript const client = new acme.Client({ directoryUrl: 'https://acme-provider.example.com/directory-url', accountKey: 'Private key goes here', externalAccountBinding: { kid: 'YOUR-EAB-KID', hmacKey: 'YOUR-EAB-HMAC-KEY', }, }); ``` -------------------------------- ### Generate RSA Private Key Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Use the crypto utility to generate a new RSA private key. ```javascript const { crypto } = require('acme-client'); await crypto.createPrivateRsaKey() ``` -------------------------------- ### Client Constructor: Invalid Key Format Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/errors.md This error occurs if the provided account key is not a valid RSA or ECDSA private key in PEM format. Ensure the key is correctly formatted and readable. ```javascript const key = fs.readFileSync('/path/to/key.pem', 'utf-8'); const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.production, accountKey: key, // String or Buffer, both work }); ``` -------------------------------- ### Configure HTTPS Proxy Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/utilities.md Configures an HTTPS proxy for client requests using the 'https' module. Ensure the 'https' module is available in your environment. ```javascript const acme = require('acme-client'); // HTTPS proxy acme.axios.defaults.httpsAgent = new (require('https')).Agent({ proxy: 'https://proxy.example.com:8080' }); ``` -------------------------------- ### createPrivateKey Source: https://github.com/publishlab/node-acme-client/blob/master/docs/crypto.md Alias for createPrivateRsaKey(). ```APIDOC ## createPrivateKey ### Description Alias of `createPrivateRsaKey()`. ### Method N/A (Function Call) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Returns * **Promise<buffer>** - A promise that resolves to a buffer containing the private RSA key. ``` -------------------------------- ### Create ACME Account and Order Source: https://github.com/publishlab/node-acme-client/blob/master/README.md Use these methods to programmatically create an ACME account and initiate an order for certificates. Ensure `termsOfServiceAgreed` is set to true and provide valid contact information. ```javascript const account = await client.createAccount({ termsOfServiceAgreed: true, contact: ['mailto:test@example.com'], }); const order = await client.createOrder({ identifiers: [ { type: 'dns', value: 'example.com' }, { type: 'dns', value: '*.example.com' }, ], }); ``` -------------------------------- ### Migrate readCsrDomains and readCertificateInfo to be non-promise Source: https://github.com/publishlab/node-acme-client/blob/master/docs/upgrade-v5.md The `readCsrDomains` and `readCertificateInfo` methods no longer return promises, providing their results directly. This change is non-breaking if `await` is used. ```javascript // Before const domains = await acme.forge.readCsrDomains(csr); const info = await acme.forge.readCertificateInfo(certificate); // After const domains = acme.crypto.readCsrDomains(csr); const info = acme.crypto.readCertificateInfo(certificate); ``` -------------------------------- ### Authorization and Challenges Methods Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Methods for managing authorizations and completing various challenge types to prove domain ownership. ```APIDOC ## Authorization & Challenges Methods ### `getAuthorizations(order)` **Description**: Retrieve the challenges associated with an order. **Parameters**: - `order` (string) - Required - The order identifier. ### `getChallengeKeyAuthorization(challenge)` **Description**: Compute the key authorization value for a given challenge. **Parameters**: - `challenge` (object) - Required - The challenge object. ### `verifyChallenge(authz, challenge)` **Description**: Internal method to verify a challenge. **Parameters**: - `authz` (object) - Required - The authorization object. - `challenge` (object) - Required - The challenge object. ### `completeChallenge(challenge)` **Description**: Report the completion of a challenge. **Parameters**: - `challenge` (object) - Required - The challenge object. ### `deactivateAuthorization(authz)` **Description**: Deactivate an authorization. **Parameters**: - `authz` (object) - Required - The authorization object. ``` -------------------------------- ### getPublicKey Source: https://github.com/publishlab/node-acme-client/blob/master/docs/crypto.md Derives a public key from a given private key in PEM format. ```APIDOC ## getPublicKey ### Description Get a public key derived from a RSA or ECDSA key. ### Method N/A (Function Call) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters * **keyPem** (string) - Required - The private key in PEM format. ### Returns * **buffer** - A buffer containing the public key. ``` -------------------------------- ### getPublicKey(keyPem) Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/crypto.md Derives a public key from a given private or public key in PEM format. ```APIDOC ## getPublicKey(keyPem) ### Description Derives a public key from a private key (RSA or ECDSA). ### Method Not applicable (SDK function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **keyPem** (buffer|string) - Required - PEM encoded private or public key ### Returns `Buffer` — PEM encoded public key ### Throws Error if key format is invalid ### Example ```javascript const privateKey = await crypto.createPrivateRsaKey(); const publicKey = crypto.getPublicKey(privateKey); console.log(publicKey.toString()); ``` ``` -------------------------------- ### Configure Client with Backoff Settings Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/api-reference/utilities.md Configure the ACME client with custom exponential backoff parameters for retries. Set the maximum number of attempts, minimum initial delay, and maximum delay between retries. ```javascript const client = new acme.Client({ directoryUrl, accountKey, backoffAttempts: 10, // Max retries backoffMin: 5000, // Initial delay (ms) backoffMax: 30000, // Maximum delay (ms) }); ``` -------------------------------- ### Access Google Directory URLs Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Access predefined directory URLs for Google staging and production environments. ```javascript const { directory } = require('acme-client'); directory.google.staging directory.google.production ``` -------------------------------- ### Access BuyPass Directory URLs Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/README.md Access predefined directory URLs for BuyPass staging and production environments. ```javascript const { directory } = require('acme-client'); directory.buypass.staging directory.buypass.production ``` -------------------------------- ### Configure HTTP Client Proxy and Timeout Source: https://github.com/publishlab/node-acme-client/blob/master/_autodocs/configuration.md Customize the default Axios HTTP client settings to include proxy configuration and request timeouts. This is useful when running behind a proxy or needing to control request duration. ```javascript const acme = require('acme-client'); // Set HTTP proxy acme.axios.defaults.proxy = { host: '127.0.0.1', port: 9000, }; // Set timeout acme.axios.defaults.timeout = 30000; // Set custom user agent acme.axios.defaults.headers.common['User-Agent'] = 'MyClient/1.0'; ``` -------------------------------- ### Create New Account with Contact Info Source: https://github.com/publishlab/node-acme-client/blob/master/docs/client.md Create a new ACME account and provide contact information. The contact should be an array of strings, typically email addresses. ```js const account = await client.createAccount({ termsOfServiceAgreed: true, contact: ['mailto:test@example.com'], }); ``` -------------------------------- ### Migrate getPemBody to getPemBodyAsB64u Source: https://github.com/publishlab/node-acme-client/blob/master/docs/upgrade-v5.md The `getPemBody` method is renamed to `getPemBodyAsB64u` and now returns a Base64URL-encoded PEM body instead of a standard Base64-encoded one. This is a breaking change. ```javascript // Before const body = acme.forge.getPemBody(pem); // After const body = acme.crypto.getPemBodyAsB64u(pem); ``` -------------------------------- ### Create CSR with Alt Names Source: https://github.com/publishlab/node-acme-client/blob/master/docs/forge.md Generates a Certificate Signing Request with specified alternative domain names. Defaults to a 2048-bit key. ```javascript const [certificateKey, certificateRequest] = await acme.forge.createCsr({ altNames: ['test.example.com'], }); ``` -------------------------------- ### Migrate getModulus and getPublicExponent to getJwk Source: https://github.com/publishlab/node-acme-client/blob/master/docs/upgrade-v5.md The `getModulus` and `getPublicExponent` methods have been removed and replaced by the `getJwk` method, which returns the JWK representation of the key. This is a breaking change. ```javascript // Before const mod = await acme.forge.getModulus(key); const exp = await acme.forge.getPublicExponent(key); // After const { e, n } = acme.crypto.getJwk(key); ```