### Create ACME Client with Options Source: https://context7.com/eggsampler/acme/llms.txt Initializes a new ACME client by fetching the directory. Configure HTTP timeout, custom transport, user-agent suffix, and retry count using variadic OptionFunc values. Built-in directory URLs like LetsEncryptProduction are available. ```go import ( "log" "time" "github.com/eggsampler/acme/v3" ) // Connect to Let's Encrypt staging with a custom timeout client, err := acme.NewClient(acme.LetsEncryptStaging, acme.WithHTTPTimeout(30*time.Second), acme.WithUserAgentSuffix("myapp/1.0"), acme.WithRetryCount(3), ) if err != nil { log.Fatalf("failed to connect to ACME directory: %v", err) } // Inspect the directory dir := client.Directory() log.Printf("NewAccount URL: %s", dir.NewAccount) log.Printf("Terms of Service: %s", dir.Meta.TermsOfService) log.Printf("ARI supported: %v", dir.RenewalInfo != "") ``` -------------------------------- ### Download Primary and Alternate Certificate Chains Source: https://context7.com/eggsampler/acme/llms.txt Fetches the primary certificate chain and any alternate chains (e.g., cross-signed) provided via `Link: rel="alternate"` headers. It returns a map where keys are certificate URLs and values are the corresponding certificate chains. ```go allChains, err := client.FetchAllCertificates(account, order.Certificate) if err != nil { log.Fatalf("fetch all certificates failed: %v", err) } for url, chain := range allChains { log.Printf("Chain at %s: issuer=%s", url, chain[0].Issuer.CommonName) } ``` -------------------------------- ### Configure Client Behavior with NewClient Options Source: https://context7.com/eggsampler/acme/llms.txt Customize the underlying HTTP client and request behavior using OptionFunc values when creating a new ACME client. This includes setting HTTP timeouts, providing custom CA roots, skipping TLS verification for testing, or supplying a pre-configured http.Client. ```go import ( "crypto/tls" "crypto/x509" "net/http" "time" "github.com/eggsampler/acme/v3" ) // Custom HTTP timeout client, _ := acme.NewClient(acme.LetsEncryptStaging, acme.WithHTTPTimeout(15*time.Second)) ``` ```go // Accept a custom CA root (e.g., Pebble test CA) pool := x509.NewCertPool() pool.AppendCertsFromPEM(pebbleRootPEM) client, _ = acme.NewClient("https://localhost:14000/dir", acme.WithRootCerts(pool)) ``` ```go // Skip TLS verification (test environments only) client, _ = acme.NewClient("https://localhost:14000/dir", acme.WithInsecureSkipVerify()) ``` ```go // Bring your own http.Client myHTTP := &http.Client{ Timeout: 20 * time.Second, Transport: myCustomTransport, } client, _ = acme.NewClient(acme.LetsEncryptStaging, acme.WithHTTPClient(myHTTP)) ``` ```go // Accept-Language and User-Agent customization client, _ = acme.NewClient(acme.LetsEncryptStaging, acme.WithAcceptLanguage("en-US"), acme.WithUserAgentSuffix("myservice/2.0"), acme.WithRetryCount(10), ) ``` -------------------------------- ### Fetch Authorization Object Source: https://context7.com/eggsampler/acme/llms.txt Retrieves an authorization from a URL provided in an order. Populates `ChallengeMap` and `ChallengeTypes`, and pre-computes `KeyAuthorization` for each challenge. Useful for accessing specific challenge details like token and key. ```go for _, authURL := range order.Authorizations { auth, err := client.FetchAuthorization(account, authURL) if err != nil { log.Fatalf("fetch authorization failed: %v", err) } log.Printf("Domain: %s, Status: %s", auth.Identifier.Value, auth.Status) log.Printf("Available challenges: %v", auth.ChallengeTypes) if auth.Status == "valid" { continue // already satisfied } // Access a specific challenge type directly chal, ok := auth.ChallengeMap[acme.ChallengeTypeHTTP01] if !ok { log.Fatalf("http-01 challenge not available") } log.Printf("Token: %s", chal.Token) log.Printf("KeyAuthorization: %s", chal.KeyAuthorization) } ``` -------------------------------- ### NewClient — Create an ACME client Source: https://context7.com/eggsampler/acme/llms.txt Creates a new ACME Client by fetching the directory from the given URL. Options can be provided to configure HTTP timeout, custom transport, user-agent suffix, and retry count. Built-in directory URL constants are available for Let's Encrypt and ZeroSSL production and staging environments. ```APIDOC ## NewClient — Create an ACME client ### Description Creates a new ACME `Client` by fetching the directory from the given URL. Accepts variadic `OptionFunc` values to configure HTTP timeout, custom transport, user-agent suffix, retry count, etc. Built-in directory URL constants are provided: `LetsEncryptProduction`, `LetsEncryptStaging`, and `ZeroSSLProduction`. ### Usage Example ```go import ( "log" "time" "github.com/eggsampler/acme/v3" ) // Connect to Let's Encrypt staging with a custom timeout client, err := acme.NewClient(acme.LetsEncryptStaging, acme.WithHTTPTimeout(30*time.Second), acme.WithUserAgentSuffix("myapp/1.0"), acme.WithRetryCount(3), ) if err != nil { log.Fatalf("failed to connect to ACME directory: %v", err) } // Inspect the directory dir := client.Directory() log.Printf("NewAccount URL: %s", dir.NewAccount) log.Printf("Terms of Service: %s", dir.Meta.TermsOfService) log.Printf("ARI supported: %v", dir.RenewalInfo != "") ``` ``` -------------------------------- ### Fetch Order List Source: https://context7.com/eggsampler/acme/llms.txt Fetches a paginated list of order URLs associated with an account. The `Next` field in the response contains the URL for the next page if it exists. ```go orderList, err := client.FetchOrderList(account) if err != nil { log.Fatalf("order list failed: %v", err) } for _, orderURL := range orderList.Orders { log.Printf("Order: %s", orderURL) } // orderList.Next contains the URL for the next page, if paginated ``` -------------------------------- ### FetchAuthorization Source: https://context7.com/eggsampler/acme/llms.txt Retrieves an authorization object from a URL provided in an order. It populates challenge details and pre-computes the `KeyAuthorization` for each challenge. Returns the `Authorization` object. ```APIDOC ## FetchAuthorization — Fetch an authorization object Retrieves an authorization from the URL provided in an order. Populates `ChallengeMap` (keyed by challenge type string) and `ChallengeTypes` (list of available types) for easy access, and pre-computes `KeyAuthorization` for each challenge. ### Method GET ### Endpoint `/authorization/{authURL}` (example, actual endpoint may vary) ### Parameters #### Path Parameters - `authURL` (string) - The URL of the authorization object to retrieve. #### Query Parameters None #### Request Body None ### Request Example `GET /authorization/some-auth-url` ### Response #### Success Response (200) - `Authorization` (object) - The authorization object, containing identifier, status, challenge types, and challenge details. #### Response Example ```json { "Authorization": { "Identifier": { "Type": "dns", "Value": "example.com" }, "Status": "pending", "ChallengeTypes": ["http-01", "dns-01"], "ChallengeMap": { "http-01": { "Token": "some-token", "KeyAuthorization": "key-auth-string" }, ... } } } ``` ``` -------------------------------- ### FetchCertificates Source: https://context7.com/eggsampler/acme/llms.txt Downloads and parses the PEM-encoded certificate chain from the URL provided by a finalized order. Returns a slice of `*x509.Certificate` (leaf first, then intermediates). ```APIDOC ## FetchCertificates ### Description Downloads and parses the PEM-encoded certificate chain from the URL provided by a finalized order. Returns a slice of `*x509.Certificate` (leaf first, then intermediates). ### Method GET (implied by client.FetchCertificates) ### Endpoint Not explicitly defined, uses the certificate URL from a finalized order. ### Parameters - **account**: The account object used for authentication. - **certificateURL**: The URL of the certificate chain to fetch. ### Request Example ```go certs, err := client.FetchCertificates(account, order.Certificate) ``` ### Response #### Success Response (200) - **certs** ([]*x509.Certificate): A slice of parsed certificates, with the leaf certificate first, followed by intermediates. #### Response Example ```go log.Printf("Issued cert CN: %s, expires: %s", certs[0].Subject.CommonName, certs[0].NotAfter) ``` ``` -------------------------------- ### Respond to HTTP-01 Challenge and Poll for Completion Source: https://context7.com/eggsampler/acme/llms.txt Writes the challenge token to the webroot for HTTP-01 challenges. Then, it notifies the ACME server and polls until the challenge is validated. Ensure the webroot is accessible by the ACME server. ```go import ( "io/ioutil" "os" "path/filepath" ) // HTTP-01: write key authorization to webroot chal := auth.ChallengeMap[acme.ChallengeTypeHTTP01] tokenPath := filepath.Join("/var/www/html/.well-known/acme-challenge", chal.Token) if err := ioutil.WriteFile(tokenPath, []byte(chal.KeyAuthorization), 0644); err != nil { log.Fatalf("failed to write challenge file: %v", err) } deferal os.Remove(tokenPath) // Notify server and wait for validation chal, err = client.UpdateChallenge(account, chal) if err != nil { log.Fatalf("challenge validation failed: %v", err) } log.Printf("Challenge status: %s", chal.Status) // "valid" ``` -------------------------------- ### Submit New Certificate Order Source: https://context7.com/eggsampler/acme/llms.txt Initiates a new certificate order for one or more domain identifiers. `NewOrderDomains` is a convenience wrapper for plain domain strings. Returns an `Order` containing authorization URLs. ```go // Using explicit Identifier structs (supports non-DNS types too) order, err := client.NewOrder(account, []acme.Identifier{ {Type: "dns", Value: "example.com"}, {Type: "dns", Value: "www.example.com"}, }) if err != nil { log.Fatalf("new order failed: %v", err) } log.Printf("Order URL: %s, Status: %s", order.URL, order.Status) log.Printf("Authorizations to fulfill: %d", len(order.Authorizations)) // Convenience form order, err = client.NewOrderDomains(account, "example.com", "www.example.com") if err != nil { log.Fatalf("new order failed: %v", err) } ``` -------------------------------- ### NewAccountOptions with External Account Binding Source: https://context7.com/eggsampler/acme/llms.txt For Certificate Authorities requiring External Account Binding (EAB), such as ZeroSSL, use `NewAcctOptExternalAccountBinding` to attach EAB credentials to the account creation request. ```APIDOC ## NewAccountOptions with External Account Binding — ZeroSSL / EAB registration ### Description For CAs that require External Account Binding (e.g., ZeroSSL), use `NewAcctOptExternalAccountBinding` to attach EAB credentials to the account creation request. ### Usage Example ```go import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "log" "os" "github.com/eggsampler/acme/v3" ) client, err := acme.NewClient(acme.ZeroSSLProduction) if err != nil { log.Fatalf("client error: %v", err) } privKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) eab := acme.ExternalAccountBinding{ KeyIdentifier: os.Getenv("EAB_KID"), // from ZeroSSL developer panel MacKey: os.Getenv("EAB_HMAC_KEY"), // base64url-encoded HMAC key Algorithm: "HS256", HashFunc: crypto.SHA256, } account, err := client.NewAccountOptions(privKey, acme.NewAcctOptAgreeTOS(), acme.NewAcctOptExternalAccountBinding(eab), ) if err != nil { log.Fatalf("EAB account registration failed: %v", err) } log.Printf("ZeroSSL account: %s", account.URL) ``` ``` -------------------------------- ### FetchAllCertificates Source: https://context7.com/eggsampler/acme/llms.txt Fetches the primary certificate chain and any alternate chains provided via `Link: rel="alternate"` headers (e.g., cross-signed chains). Returns a map from certificate URL to chain. ```APIDOC ## FetchAllCertificates ### Description Fetches the primary certificate chain and any alternate chains provided via `Link: rel="alternate"` headers (e.g., cross-signed chains). Returns a map from certificate URL to chain. ### Method GET (implied by client.FetchAllCertificates) ### Endpoint Not explicitly defined, uses the certificate URL from a finalized order. ### Parameters - **account**: The account object used for authentication. - **certificateURL**: The URL of the primary certificate chain. ### Request Example ```go allChains, err := client.FetchAllCertificates(account, order.Certificate) ``` ### Response #### Success Response (200) - **allChains** (map[string][]*x509.Certificate): A map where keys are certificate URLs and values are the corresponding certificate chains. #### Response Example ```go for url, chain := range allChains { log.Printf("Chain at %s: issuer=%s", url, chain[0].Issuer.CommonName) } ``` ``` -------------------------------- ### Automatic On-Demand Certificate Manager (AutoCert) Source: https://context7.com/eggsampler/acme/llms.txt A stateful TLS certificate manager that issues and caches certificates. Implements `tls.Config.GetCertificate` and provides an HTTP handler for http-01 challenges. Optionally persists certificates and keys. ```go import ( "crypto/tls" "log" "net/http" "github.com/eggsampler/acme/v3" ) m := &acme.AutoCert{ DirectoryURL: acme.LetsEncryptProduction, CacheDir: "/var/cache/acme", HostCheck: acme.WhitelistHosts("example.com", "www.example.com"), // Optional: hook called before each challenge is submitted PreUpdateChallengeHook: func(acc acme.Account, chal acme.Challenge) { log.Printf("Preparing challenge for token: %s", chal.Token) }, } // Start HTTP server to serve http-01 challenge tokens (also redirects HTTP→HTTPS) go func() { log.Fatal(http.ListenAndServe(":80", m.HTTPHandler(nil))) }() // Start HTTPS server; certificates are issued/renewed on first TLS handshake server := &http.Server{ Addr: ":443", TLSConfig: &tls.Config{ GetCertificate: m.GetCertificate, }, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, secure world!")) }), } log.Fatal(server.ListenAndServeTLS("", "")) ``` -------------------------------- ### Import ACME Go Module Source: https://github.com/eggsampler/acme/blob/master/README.md Import the ACME Go module into your project. Note the use of the major version in the import path. ```go import "github.com/eggsampler/acme/v3" ``` -------------------------------- ### AutoCert Source: https://context7.com/eggsampler/acme/llms.txt Provides a high-level, stateful TLS certificate manager that handles certificate issuance, caching, and serving HTTP-01 challenge tokens. ```APIDOC ## AutoCert — Automatic on-demand certificate manager ### Description `AutoCert` is a high-level, stateful TLS certificate manager that issues and caches certificates on first use. It implements `tls.Config.GetCertificate` and provides an HTTP handler for http-01 challenge tokens. Certificates and account keys are optionally persisted to a `CacheDir`. ### Usage ```go import ( "crypto/tls" "log" "net/http" "github.com/eggsampler/acme/v3" ) m := &acme.AutoCert{ DirectoryURL: acme.LetsEncryptProduction, CacheDir: "/var/cache/acme", HostCheck: acme.WhitelistHosts("example.com", "www.example.com"), // Optional: hook called before each challenge is submitted PreUpdateChallengeHook: func(acc acme.Account, chal acme.Challenge) { log.Printf("Preparing challenge for token: %s", chal.Token) }, } // Start HTTP server to serve http-01 challenge tokens (also redirects HTTP→HTTPS) go func() { log.Fatal(http.ListenAndServe(":80", m.HTTPHandler(nil))) }() // Start HTTPS server; certificates are issued/renewed on first TLS handshake server := &http.Server{ Addr: ":443", TLSConfig: &tls.Config{ GetCertificate: m.GetCertificate, }, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, secure world!")) }), } log.Fatal(server.ListenAndServeTLS("", "")) ``` ### Configuration Options - `DirectoryURL`: The ACME directory endpoint. - `CacheDir`: Path to a directory for caching certificates and keys. - `HostCheck`: A function to validate allowed hosts. - `PreUpdateChallengeHook`: An optional hook executed before challenge submission. ``` -------------------------------- ### NewAccountOptions / NewAccount — Register or fetch an ACME account Source: https://context7.com/eggsampler/acme/llms.txt Registers a new account or fetches an existing one using composable options. The `Account` struct returned contains the private key, account URL, and JWK thumbprint necessary for challenge key-authorizations. A convenience wrapper `NewAccount` is available for backwards compatibility. ```APIDOC ## NewAccountOptions / NewAccount — Register or fetch an ACME account ### Description `NewAccountOptions` registers a new account (or fetches an existing one) using composable `NewAccountOptionFunc` options. The older `NewAccount` is a convenience wrapper kept for backwards compatibility. The returned `Account` carries the private key, account URL, and computed JWK thumbprint used for challenge key-authorizations. ### Usage Example (New Registration) ```go import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "log" "github.com/eggsampler/acme/v3" ) privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { log.Fatalf("key generation failed: %v", err) } // Register a new account, agreeing to TOS and providing a contact account, err := client.NewAccountOptions(privKey, acme.NewAcctOptAgreeTOS(), acme.NewAcctOptWithContacts("mailto:admin@example.com"), ) if err != nil { log.Fatalf("account registration failed: %v", err) } log.Printf("Account URL: %s", account.URL) log.Printf("Account thumbprint: %s", account.Thumbprint) ``` ### Usage Example (Fetch Existing) ```go // Fetch an existing account (onlyReturnExisting = true) existingAccount, err := client.NewAccountOptions(privKey, acme.NewAcctOptOnlyReturnExisting(), ) if err != nil { log.Fatalf("account lookup failed: %v", err) } log.Printf("Existing account status: %s", existingAccount.Status) ``` ``` -------------------------------- ### Respond to DNS-01 Challenge and Poll for Completion Source: https://context7.com/eggsampler/acme/llms.txt Encodes the key authorization for DNS-01 challenges and logs the TXT record value. After setting the DNS record, it notifies the ACME server and polls for validation. This method is for DNS-01 challenges. ```go // DNS-01: use the encoded key authorization as the TXT record value dnsChal := auth.ChallengeMap[acme.ChallengeTypeDNS01] txtValue := acme.EncodeDNS01KeyAuthorization(dnsChal.KeyAuthorization) log.Printf("Set TXT record _acme-challenge.example.com = %s", txtValue) // ... set DNS record, then: dnsChal, err = client.UpdateChallenge(account, dnsChal) if err != nil { log.Fatalf("DNS challenge failed: %v", err) } ``` -------------------------------- ### Encode DNS-01 TXT Record Value Source: https://context7.com/eggsampler/acme/llms.txt Computes the base64url-encoded SHA-256 hash of a challenge's key authorization. This value is used for the `_acme-challenge.` DNS TXT record. After setting the record, the challenge must be updated. ```go dnsChal := auth.ChallengeMap[acme.ChallengeTypeDNS01] txtRecord := acme.EncodeDNS01KeyAuthorization(dnsChal.KeyAuthorization) log.Printf("Add DNS TXT record: _acme-challenge.%s = %s", auth.Identifier.Value, txtRecord) // After setting the record in your DNS provider, update the challenge dnsChal, err = client.UpdateChallenge(account, dnsChal) if err != nil { log.Fatalf("DNS-01 challenge failed: %v", err) } ``` -------------------------------- ### NewOrder / NewOrderDomains Source: https://context7.com/eggsampler/acme/llms.txt Initiates a new certificate order for one or more domain identifiers. `NewOrderDomains` is a convenience wrapper for plain domain strings. Returns an `Order` object with authorization URLs. ```APIDOC ## NewOrder / NewOrderDomains — Submit a new certificate order Initiates an order for one or more domain identifiers. `NewOrderDomains` is a convenience wrapper that accepts plain domain strings. Returns an `Order` containing authorization URLs to fulfill. ### Method POST ### Endpoint `/new-order` (example, actual endpoint may vary) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - `account` (object) - The account object placing the order. - `identifiers` (array of objects) - A list of domain identifiers for the order. Each object should have `Type` (e.g., "dns") and `Value` (e.g., "example.com"). ### Request Example ```json { "account": { ... }, "identifiers": [ { "Type": "dns", "Value": "example.com" }, { "Type": "dns", "Value": "www.example.com" } ] } ``` ### Response #### Success Response (200) - `Order` (object) - The newly created order object, containing URL and status, and a list of authorizations. #### Response Example ```json { "Order": { "URL": "order-url", "Status": "pending", "Authorizations": ["auth-url-1", "auth-url-2"] } } ``` ``` -------------------------------- ### Fetch Source: https://context7.com/eggsampler/acme/llms.txt A generic helper function to perform authenticated POST-as-GET requests to ACME resources. ```APIDOC ## Fetch — Generic POST-as-GET helper ### Description Performs an authenticated POST-as-GET request to any ACME resource URL and unmarshals the JSON response into the provided interface. ### Method Signature `err := client.Fetch(account, order.URL, &orderDetails)` ### Parameters - `account`: The account object for authentication. - `order.URL`: The URL of the ACME resource to fetch. - `&orderDetails`: A pointer to an interface where the JSON response will be unmarshaled. ### Returns - `err`: An error object if the fetch operation failed. ``` -------------------------------- ### NewClient Option Functions Source: https://context7.com/eggsampler/acme/llms.txt A set of OptionFunc values for customizing the underlying HTTP client and request behaviour when creating a new ACME client. ```APIDOC ## `NewClient` option functions — Configure client behaviour A set of `OptionFunc` values for customizing the underlying HTTP client and request behaviour. ### Custom HTTP timeout ```go client, _ := acme.NewClient(acme.LetsEncryptStaging, acme.WithHTTPTimeout(15*time.Second)) ``` ### Accept a custom CA root (e.g., Pebble test CA) ```go pool := x509.NewCertPool() pool.AppendCertsFromPEM(pebbleRootPEM) client, _ = acme.NewClient("https://localhost:14000/dir", acme.WithRootCerts(pool)) ``` ### Skip TLS verification (test environments only) ```go client, _ = acme.NewClient("https://localhost:14000/dir", acme.WithInsecureSkipVerify()) ``` ### Bring your own http.Client ```go myHTTP := &http.Client{ Timeout: 20 * time.Second, Transport: myCustomTransport, } client, _ = acme.NewClient(acme.LetsEncryptStaging, acme.WithHTTPClient(myHTTP)) ``` ### Accept-Language and User-Agent customization ```go client, _ = acme.NewClient(acme.LetsEncryptStaging, acme.WithAcceptLanguage("en-US"), acme.WithUserAgentSuffix("myservice/2.0"), acme.WithRetryCount(10), ) ``` ``` -------------------------------- ### Generic POST-as-GET Helper with ACME Source: https://context7.com/eggsampler/acme/llms.txt Performs an authenticated POST-as-GET request to an ACME resource URL and unmarshals the JSON response. Useful for fetching various ACME resource details. ```go var orderDetails acme.Order err := client.Fetch(account, order.URL, &orderDetails) if err != nil { log.Fatalf("fetch failed: %v", err) } log.Printf("Order status via Fetch: %s", orderDetails.Status) ``` -------------------------------- ### Register or Fetch ACME Account Source: https://context7.com/eggsampler/acme/llms.txt Registers a new ACME account or fetches an existing one using composable options. The Account struct contains the private key, URL, and JWK thumbprint. Use `NewAcctOptOnlyReturnExisting()` to fetch an existing account without registering. ```go import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "log" "github.com/eggsampler/acme/v3" ) privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { log.Fatalf("key generation failed: %v", err) } // Register a new account, agreeing to TOS and providing a contact account, err := client.NewAccountOptions(privKey, acme.NewAcctOptAgreeTOS(), acme.NewAcctOptWithContacts("mailto:admin@example.com"), ) if err != nil { log.Fatalf("account registration failed: %v", err) } log.Printf("Account URL: %s", account.URL) log.Printf("Account thumbprint: %s", account.Thumbprint) // Fetch an existing account (onlyReturnExisting = true) existingAccount, err := client.NewAccountOptions(privKey, acme.NewAcctOptOnlyReturnExisting(), ) if err != nil { log.Fatalf("account lookup failed: %v", err) } log.Printf("Existing account status: %s", existingAccount.Status) ``` -------------------------------- ### FetchOrderList Source: https://context7.com/eggsampler/acme/llms.txt Fetches a paginated list of order URLs associated with a specific account. Returns an object containing a list of orders and a URL for the next page if available. ```APIDOC ## FetchOrderList — List all orders for an account Fetches the paginated list of order URLs associated with an account. ### Method GET ### Endpoint `/orders` (example, actual endpoint may vary) ### Parameters #### Path Parameters None #### Query Parameters - `accountId` (string) - The ID of the account to fetch orders for. - `page` (integer, optional) - The page number to retrieve. ### Request Example `GET /orders?accountId=some-account-id&page=1` ### Response #### Success Response (200) - `Orders` (array of strings) - A list of order URLs. - `Next` (string, optional) - The URL for the next page of results. #### Response Example ```json { "Orders": ["order-url-1", "order-url-2"], "Next": "/orders?accountId=some-account-id&page=2" } ``` ``` -------------------------------- ### Download Issued Certificate Chain Source: https://context7.com/eggsampler/acme/llms.txt Downloads and parses the PEM-encoded certificate chain from a given URL. It returns a slice of `*x509.Certificate` objects, with the leaf certificate first, followed by intermediates. The downloaded chain is then written to a file named 'cert.pem'. ```go import ( "crypto/x509" "encoding/pem" "os" ) certs, err := client.FetchCertificates(account, order.Certificate) if err != nil { log.Fatalf("fetch certificates failed: %v", err) } // Write PEM chain to file f, _ := os.Create("cert.pem") deferal f.Close() for _, c := range certs { pem.Encode(f, &pem.Block{Type: "CERTIFICATE", Bytes: c.Raw}) } log.Printf("Issued cert CN: %s, expires: %s", certs[0].Subject.CommonName, certs[0].NotAfter) ``` -------------------------------- ### RenewalInfo.ShouldRenewAt Source: https://context7.com/eggsampler/acme/llms.txt Computes the optimal time to attempt certificate renewal based on the current time and a maximum tolerance for waiting. ```APIDOC ## RenewalInfo.ShouldRenewAt — Compute optimal renewal time ### Description Given the current time and the maximum duration the caller is willing to sleep, returns the time at which renewal should be attempted (a random point within the suggested window), or `nil` if the renewal window is too far in the future. ### Method Signature `shouldRenewAt := ri.ShouldRenewAt(time.Now(), 24*time.Hour)` ### Parameters - `time.Now()`: The current time. - `24*time.Hour`: The maximum duration the caller is willing to wait for renewal. ### Returns - `shouldRenewAt`: A `time.Time` object indicating when to renew, or `nil` if renewal is not needed within the tolerance. ``` -------------------------------- ### Problem Source: https://context7.com/eggsampler/acme/llms.txt `Problem` implements the `error` interface and represents an RFC 7807 problem document returned by the ACME server. It includes a `Type` URI, human-readable `Detail`, HTTP `Status`, optional `Instance` URL, and a `SubProblems` slice for per-identifier errors in multi-domain orders. ```APIDOC ## `Problem` — ACME error type `Problem` implements the `error` interface and represents an RFC 7807 problem document returned by the ACME server. It includes a `Type` URI, human-readable `Detail`, HTTP `Status`, optional `Instance` URL, and a `SubProblems` slice for per-identifier errors in multi-domain orders. ```go order, err := client.NewOrder(account, []acme.Identifier{ {Type: "dns", Value: "example.com"}, }) if err != nil { if prob, ok := err.(acme.Problem); ok { log.Printf("ACME error type: %s", prob.Type) log.Printf("ACME error detail: %s", prob.Detail) log.Printf("HTTP status: %d", prob.Status) for _, sub := range prob.SubProblems { log.Printf(" sub-problem for %s: %s", sub.Identifier.Value, sub.Detail) } } else { log.Fatalf("non-ACME error: %v", err) } } ``` ``` -------------------------------- ### EncodeDNS01KeyAuthorization Source: https://context7.com/eggsampler/acme/llms.txt Computes the base64url-encoded SHA-256 hash of a challenge's key authorization. The result is the value to place in the `_acme-challenge.` DNS TXT record. ```APIDOC ## `EncodeDNS01KeyAuthorization` — Encode DNS-01 TXT record value Computes the base64url-encoded SHA-256 hash of a challenge's key authorization. The result is the value to place in the `_acme-challenge.` DNS TXT record. ```go dnsChal := auth.ChallengeMap[acme.ChallengeTypeDNS01] txtRecord := acme.EncodeDNS01KeyAuthorization(dnsChal.KeyAuthorization) log.Printf("Add DNS TXT record: _acme-challenge.%s = %s", auth.Identifier.Value, txtRecord) // After setting the record in your DNS provider, update the challenge dnsChal, err = client.UpdateChallenge(account, dnsChal) if err != nil { log.Fatalf("DNS-01 challenge failed: %v", err) } ``` ``` -------------------------------- ### Fetch ACME Renewal Information (ARI) Source: https://context7.com/eggsampler/acme/llms.txt Fetches the server-suggested renewal window for a certificate using ACME Renewal Information (ARI). Requires the ACME server to support ARI. Handles cases where ARI is not supported. ```go ri, err := client.GetRenewalInfo(certs[0]) if err != nil { if err == acme.ErrRenewalInfoNotSupported { log.Println("ARI not supported by this CA") } else { log.Fatalf("get renewal info failed: %v", err) } } log.Printf("Renew between: %s — %s", ri.SuggestedWindow.Start, ri.SuggestedWindow.End) if ri.ExplanationURL != "" { log.Printf("Explanation: %s", ri.ExplanationURL) } ``` -------------------------------- ### ReplacementOrder Source: https://context7.com/eggsampler/acme/llms.txt Creates a new order marked as replacing a previously-issued certificate, eligible for rate-limit exemptions under ACME Renewal Information. Requires the server to advertise a `renewalInfo` endpoint. Returns the new `Order` object. ```APIDOC ## ReplacementOrder — ARI replacement order Creates a new order marked as replacing a previously-issued certificate, making it eligible for rate-limit exemptions under ACME Renewal Information. Requires the ACME server to advertise a `renewalInfo` endpoint. ### Method POST ### Endpoint `/replacement-order` (example, actual endpoint may vary) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - `account` (object) - The account object placing the order. - `existingCert` (object) - The existing certificate object being replaced. - `identifiers` (array of objects) - A list of domain identifiers for the new order. ### Request Example ```json { "account": { ... }, "existingCert": { ... }, "identifiers": [ { "Type": "dns", "Value": "example.com" } ] } ``` ### Response #### Success Response (200) - `Order` (object) - The new replacement order object, including its URL and the URL of the certificate it replaces. #### Response Example ```json { "Order": { "URL": "replacement-order-url", "Replaces": "previous-cert-url", ... } } ``` ``` -------------------------------- ### Roll Over Account Key Source: https://context7.com/eggsampler/acme/llms.txt Replaces an account's private key. Both old and new keys participate in the signed inner JWS as required by RFC 8555. Requires importing crypto packages. ```go import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "log" ) newKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { log.Fatalf("key generation failed: %v", err) } account, err = client.AccountKeyChange(account, newKey) if err != nil { log.Fatalf("key rollover failed: %v", err) } // account.PrivateKey is now newKey log.Println("Key rollover successful") ``` -------------------------------- ### Generate CSR and Finalize Order for Certificate Issuance Source: https://context7.com/eggsampler/acme/llms.txt Generates an ECDSA key pair and a Certificate Signing Request (CSR) for a given domain. It then submits the CSR to finalize the order and polls for certificate issuance, respecting server retry headers. The default polling timeout is 30 seconds. ```go import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" ) // Generate certificate key pair certKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { log.Fatalf("key generation failed: %v", err) } // Build CSR tpl := &x509.CertificateRequest{ SignatureAlgorithm: x509.ECDSAWithSHA256, PublicKeyAlgorithm: x509.ECDSA, PublicKey: certKey.Public(), Subject: pkix.Name{CommonName: "example.com"}, DNSNames: []string{"example.com", "www.example.com"}, } csrDER, err := x509.CreateCertificateRequest(rand.Reader, tpl, certKey) if err != nil { log.Fatalf("CSR creation failed: %v", err) } cert, err := x509.ParseCertificateRequest(csrDER) if err != nil { log.Fatalf("CSR parse failed: %v", err) } // Finalize and wait for issuance (polls up to client.PollTimeout, default 30s) order, err = client.FinalizeOrder(account, order, cert) if err != nil { log.Fatalf("finalization failed: %v", err) } log.Printf("Order status: %s", order.Status) // "valid" log.Printf("Certificate URL: %s", order.Certificate) ``` -------------------------------- ### FetchOrder Source: https://context7.com/eggsampler/acme/llms.txt Retrieves the current state of an ACME order by its URL, useful for polling asynchronous order processing. ```APIDOC ## FetchOrder — Fetch an existing order by URL ### Description Retrieves the current state of an order from its URL. Useful for polling asynchronous order processing. ### Method Signature `order, err = client.FetchOrder(account, order.URL)` ### Parameters - `account`: The account object. - `order.URL`: The URL of the order to fetch. ### Returns - `order`: The updated order object. - `err`: An error object if fetching the order failed. ``` -------------------------------- ### Compute Optimal ACME Renewal Time Source: https://context7.com/eggsampler/acme/llms.txt Computes the optimal time to attempt certificate renewal based on the suggested window and a maximum sleep duration. Returns nil if the window is too far in the future. ```go import "time" shouldRenewAt := ri.ShouldRenewAt(time.Now(), 24*time.Hour) if shouldRenewAt == nil { log.Println("No need to renew yet; window is beyond 24h sleep tolerance") } else if shouldRenewAt.Before(time.Now().Add(time.Second)) { log.Println("Renew immediately — window is in the past or now") } else { log.Printf("Schedule renewal at: %s", shouldRenewAt) time.Sleep(time.Until(*shouldRenewAt)) // ... perform renewal } ``` -------------------------------- ### Revoke a Certificate Source: https://context7.com/eggsampler/acme/llms.txt Revokes a certificate using either the account's private key or the certificate's own private key. Supports predefined reason codes for revocation, such as `ReasonKeyCompromise` or `ReasonSuperseded`. Ensure the correct private key and reason code are provided. ```go // Revoke using the account key err := client.RevokeCertificate(account, certs[0], account.PrivateKey, acme.ReasonKeyCompromise) if err != nil { log.Fatalf("revocation failed: %v", err) } log.Println("Certificate revoked") // Revoke using the certificate's own key (kid is empty) err = client.RevokeCertificate(account, certs[0], certKey, acme.ReasonSuperseded) if err != nil { log.Fatalf("revocation failed: %v", err) } ``` -------------------------------- ### Compute JWK Thumbprint Source: https://context7.com/eggsampler/acme/llms.txt Computes the RFC 7638 JWK thumbprint (base64url-encoded SHA-256) of a public key. This thumbprint is used as the account's `Thumbprint` and in constructing `KeyAuthorization` strings. ```go thumbprint, err := acme.JWKThumbprint(account.PrivateKey.Public()) if err != nil { log.Fatalf("thumbprint computation failed: %v", err) } log.Printf("Account JWK thumbprint: %s", thumbprint) // Manually construct key authorization: keyAuth := challenge.Token + "." + thumbprint ``` -------------------------------- ### AccountKeyChange Source: https://context7.com/eggsampler/acme/llms.txt Rolls over the account's private key. Both the old and new keys are used in the signed inner JWS as required by RFC 8555. Returns the updated account object with the new key. ```APIDOC ## AccountKeyChange — Roll over account key Replaces the account's private key with a new one. Both old and new keys participate in the signed inner JWS as required by RFC 8555. ### Method POST ### Endpoint `/account-key-change` (example, actual endpoint may vary) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - `account` (object) - The account object whose key needs to be rolled over. - `newPrivateKey` (object) - The new private key to be set for the account. ### Request Example ```json { "account": { ... }, "newPrivateKey": { ... } } ``` ### Response #### Success Response (200) - `Account` (object) - The account object with the new private key. #### Response Example ```json { "Account": { ... } } ``` ``` -------------------------------- ### GetRenewalInfo Source: https://context7.com/eggsampler/acme/llms.txt Fetches the server-suggested renewal window for a certificate. This function requires the ACME server to support ARI (Automatic Renewal Information). ```APIDOC ## GetRenewalInfo — Fetch ACME Renewal Information (ARI) ### Description Fetches the server-suggested renewal window for a certificate. Returns a `RenewalInfo` with a `SuggestedWindow` (start/end times), an optional `ExplanationURL`, and a `RetryAfter` time. Requires the ACME server to support ARI (`dir.RenewalInfo` must be non-empty). ### Method Signature `ri, err := client.GetRenewalInfo(certs[0])` ### Parameters - `certs[0]`: The certificate object for which to fetch renewal information. ### Returns - `ri`: A `RenewalInfo` object containing renewal suggestions. - `err`: An error object, potentially `acme.ErrRenewalInfoNotSupported` if ARI is not supported. ``` -------------------------------- ### ZeroSSL EAB Account Registration Source: https://context7.com/eggsampler/acme/llms.txt Registers an ACME account with External Account Binding (EAB) for CAs like ZeroSSL. Requires EAB credentials (Key Identifier and MacKey) to be provided via environment variables. ```go import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "log" "os" "github.com/eggsampler/acme/v3" ) client, err := acme.NewClient(acme.ZeroSSLProduction) if err != nil { log.Fatalf("client error: %v", err) } privKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) eab := acme.ExternalAccountBinding{ KeyIdentifier: os.Getenv("EAB_KID"), // from ZeroSSL developer panel MacKey: os.Getenv("EAB_HMAC_KEY"), // base64url-encoded HMAC key Algorithm: "HS256", HashFunc: crypto.SHA256, } account, err := client.NewAccountOptions(privKey, acme.NewAcctOptAgreeTOS(), acme.NewAcctOptExternalAccountBinding(eab), ) if err != nil { log.Fatalf("EAB account registration failed: %v", err) } log.Printf("ZeroSSL account: %s", account.URL) ``` -------------------------------- ### Fetch ACME Order by URL Source: https://context7.com/eggsampler/acme/llms.txt Retrieves the current state of an ACME order from its URL. Useful for polling asynchronous order processing, especially when ignoring retry after or polling intervals. ```go // Poll order manually (useful when IgnoreRetryAfter / IgnorePolling are set) client.IgnoreRetryAfter = true client.IgnorePolling = true for { time.Sleep(time.Until(order.RetryAfter) + 2*time.Second) order, err = client.FetchOrder(account, order.URL) if err != nil { log.Fatalf("fetch order failed: %v", err) } if order.Status == "valid" { break } log.Printf("Order still processing, status: %s", order.Status) } ``` -------------------------------- ### Handle ACME Errors with Problem Type Source: https://context7.com/eggsampler/acme/llms.txt The `Problem` type implements the `error` interface for RFC 7807 problem documents from ACME servers. It includes error type, detail, status, and optional instance URLs or sub-problems for multi-domain orders. ```go order, err := client.NewOrder(account, []acme.Identifier{ {Type: "dns", Value: "example.com"}, }) if err != nil { if prob, ok := err.(acme.Problem); ok { log.Printf("ACME error type: %s", prob.Type) log.Printf("ACME error detail: %s", prob.Detail) log.Printf("HTTP status: %d", prob.Status) for _, sub := range prob.SubProblems { log.Printf(" sub-problem for %s: %s", sub.Identifier.Value, sub.Detail) } } else { log.Fatalf("non-ACME error: %v", err) } } ``` -------------------------------- ### Create ARI Replacement Order Source: https://context7.com/eggsampler/acme/llms.txt Creates a new order marked as replacing a previously-issued certificate, eligible for rate-limit exemptions under ACME Renewal Information. Requires the ACME server to advertise a `renewalInfo` endpoint. ```go // existingCert is an *x509.Certificate loaded from the currently deployed cert order, err := client.ReplacementOrder(account, existingCert, []acme.Identifier{ {Type: "dns", Value: "example.com"}, }) if err != nil { log.Fatalf("replacement order failed: %v", err) } log.Printf("Replacement order: %s, Replaces: %s", order.URL, order.Replaces) ```