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.