When a reverse proxy forwards an HTTP request received as TLS early data, what marks it, and how can the origin refuse?
answer
- the forwarding hop marks it
- one request field, value 1
- a status meaning retry later
- 425 Too Early is not a content error
- replay-safety is the application's call
basics
~20 sRFC 8470 has the forwarding hop add the Early-Data request header field with the value 1, warning the next hop the request may be a replay. An origin unwilling to act on it answers 425 (Too Early), asking for a retry after the handshake completes.
solid answer
~50 sThe hop that terminates TLS knows the request arrived in early data; the application behind it does not. RFC 8470 closes that gap with the `Early-Data` request header field, carrying the value `1`, added by an intermediary that forwards a request before the TLS handshake has completed. It is a warning, not a credential: it says this request may be a replay and the handshake may never finish. A server unwilling to process it answers `425 (Too Early)`, which is not a complaint about the request's content - it asks the client to send the identical request again once the handshake is done, at which point it is no longer early and carries no such field. Which requests may ride in early data is an application decision, not a TLS one: a turnstile payment authorisation must not, because a replayed flight is a second authorisation.
code
http · 11 linesPOST /turnstile/authorise HTTP/1.1
Host: gate-7.example
Early-Data: 1
Content-Type: application/json
Content-Length: 59
{"reader":"g7-04","amount":1200,"currency":"GBP","seq":881}
HTTP/1.1 425 Too Early
Date: Sat, 19 Sep 2026 18:41:07 GMT
Content-Length: 0go deeper
Know that a request can arrive before the handshake is finished, that the hop forwarding it says so, and that the answer may be a request to send it again later.
Name the request header field and the status code, and explain that the retry after handshake completion is the entire remedy - the request itself never changes.
Decide per route at the edge: which reads may be marked and forwarded, and where a repeat would be visible to a customer so the origin must answer 425.
Judge whether one round trip is worth giving every route an opinion about replay, against simply holding early data until the handshake completes.
## The gap this closes 0-RTT is decided at the TLS layer, but the consequences land in the application. A reverse proxy that terminates the connection sees `early_data(42)` in the `ClientHello` and knows perfectly well that the request it just read might be a copy of one it read a minute ago. Forward that request to an origin over a separate hop and all of that context is gone: the origin sees an ordinary request. RFC 8470 gives the two hops a vocabulary for it. ## The request header field `Early-Data: 1` is added by an intermediary that forwards a request before the TLS handshake with the client has completed. It carries exactly one defined value and means two things at once: - **this request may be a replay** - nothing yet rules that out; - **the handshake may not complete at all** - the client that sent it may never be confirmed. It is a description of how the request arrived, so it belongs on the request and never on a response, and it is not something an originating client sets about itself. ## The status code `425 (Too Early)` is the origin's way of declining without pretending the request was wrong. It does not mean malformed, unauthorised or conflicting. It means: I am unwilling to risk processing this now; send it again when the handshake has finished. A client that receives it retries the identical request once the connection is fully established - at which point the request is no longer early data, so no intermediary marks it, and it is processed normally. That retry is the whole mechanism. There is nothing for the client to change. ## Three ways a deployment handles early data 1. **Do not accept it.** The terminating hop declines `early_data(42)` altogether; the client resends after the handshake. Nothing downstream ever sees the question. 2. **Accept and hold.** The hop accepts early data but does not forward the request until the handshake completes, then forwards it unmarked. Zero risk downstream, and the round trip is given back. 3. **Accept and forward.** The hop forwards immediately with `Early-Data: 1`, and the origin decides per route - serve it, or answer `425 (Too Early)`. Only the third is a genuine 0-RTT deployment, and it is the one that requires the origin to have an opinion about every route. ## Which requests can actually afford it The honest answer is that the TLS layer cannot know, because replay-safety is a property of what the request *does*: - a fetch of a static asset repeats harmlessly and leaks nothing new; - a read that is metered, rate-limited or single-use is already not safe, though it looks idempotent; - anything with a side effect that must happen once - authorising a payment at a turnstile, redeeming a ticket, casting a vote - is out, and no method table makes it in. The common shortcut, "idempotent methods are fine", is too strong. Idempotence says a repeat leaves the same state; it does not say a repeat is unobservable, and a replay is an action the attacker chose the timing of. ## What the field does not give you `Early-Data: 1` does not tell the origin that a replay *happened* - only that this one could be. Detecting an actual duplicate is the TLS layer's anti-replay job, and it happens at the hop that terminated the handshake. Nor does the field relax anything: a request that arrives in early data is authenticated and authorised exactly as any other, and 0-RTT is not a reason to skip either. A useful default at the edge: mark and forward for routes that read, and answer `425 (Too Early)` everywhere a repeat would be visible to a customer - which, at a turnstile, is every request that moves money.
- What should a client do on receiving 425 (Too Early)?Send the identical request again once the TLS handshake has completed. Nothing in the request changes; it simply is not early data the second time, so no intermediary marks it and the origin processes it normally. Treating 425 as a permanent failure turns a retry signal into an outage.
- Can Early-Data appear on a response?No. It describes how a request arrived, so it is a request header field. The response side of the exchange carries the status code instead - 425 (Too Early) to ask for a retry, or an ordinary status if the origin was willing to act on the request.
- Is an idempotent method automatically safe to send as early data?No. Idempotence says a repeat leaves the same state, not that a repeat is unobservable. Metering, rate limits, one-time links and timing oracles all make a repeated read meaningful, so the application decides, not the method table.
saying these in an interview costs you the question
- Reads 425 (Too Early) as a malformed-request error
- Says the originating client sets Early-Data on its own requests
- Claims any GET is safe to send in early data
- Thinks the header field reports that a replay actually occurred
- Treats early data as a reason to relax authentication on the request