Replay-Nonce

Replay attacks against certificate management requests can compromise domain control. The Replay-Nonce response header provides a unique nonce value from an ACME server for use in the next client request, preventing such attacks.

Usage

The Automatic Certificate Management Environment (ACME) protocol automates the process of certificate issuance and renewal between clients and certificate authorities. To prevent attackers from capturing and replaying legitimate protocol messages, ACME requires each request to include a fresh nonce value in a JSON Web Signature (JWS) protected header.

The Replay-Nonce header delivers this nonce from server to client. The ACME server includes the header in every successful response to a POST request and provides the nonce in error responses as well. Each nonce is a server-generated value designed to be unpredictable and unique with high probability.

Clients extract the nonce from the header and embed the value in the protected header of their next JWS-signed request. The server verifies the nonce appears in the request and marks the value as consumed. Once used, the nonce becomes invalid for future requests, forcing clients to obtain a fresh nonce from the most recent server response.

Clients obtain their first nonce from the directory's newNonce resource before sending any signed request. A HEAD request to the endpoint returns 200 with a Replay-Nonce header, and a GET request returns 204 No Content with the same header. Every subsequent response supplies the nonce for the next request, so a well-behaved client contacts newNonce again only after discarding state or receiving a badNonce error.

When a server rejects a request due to an invalid or missing nonce, the response carries HTTP 400 Bad Request with the ACME error type urn:ietf:params:acme:error:badNonce and includes a new nonce in the Replay-Nonce header for the next attempt.

Values

The header contains an opaque string value generated by the ACME server. The format is implementation-specific. Clients treat the value as an opaque token without parsing or interpreting the content. The server controls nonce generation to ensure uniqueness and unpredictability.

Example

An ACME server response providing a nonce for the next client request. The client includes this exact value in the JWS protected header when submitting the next ACME protocol message.

Replay-Nonce: oFvnlFP1wIhRlYS2jTaXbA

A fresh nonce provided after a nonce validation failure. The server responds with status 400 and the ACME error type, but includes a new nonce the client uses to retry the request.

Replay-Nonce: 8Xk9mN2pQrLvBsFwTnYcHg

How a busy CA hands out nonces

Every successful ACME response carries a fresh Replay-Nonce, so the efficient client reuses the value from the previous response rather than calling the nonce endpoint before each request. A rejected nonce costs little: the badNonce error arrives as a 400 carrying a fresh nonce the server commits to accepting, and the retry uses exactly the supplied value, the one case where nonce pooling is forbidden.

Let's Encrypt shows the production shape. Live nonces run 51 characters, an 8-character routing prefix ahead of a 32-byte body, with the prefix identifying which nonce-service instance minted the value so any frontend routes a redemption to the instance holding the state. The implementation encrypts a counter rather than storing nonces, and forgets values by count rather than by clock, so nonce lifetime shrinks as the CA gets busier, which is why no fixed validity window appears in any documentation.

The nonce endpoint answers HEAD with 200 and GET with 204, both carrying a fresh value. The specification demands no-store caching on the endpoint, and Let's Encrypt serves no-cache instead, a literal deviation kept safe by forced revalidation, and a reminder to read live behavior alongside the specification.

See also

Last updated: August 17, 2026