Refresh-token rotation is on, and a boat's phone that lost signal mid-refresh comes back signed out - what happened?
answer
- single-use by design
- the old one is remembered, not forgotten
- a collision reveals a copy exists
- the server cannot tell who replayed
- required for public clients, says RFC 9700
basics
~20 sThe rotated refresh token reached the client's response but never arrived, so the phone replayed the old one. Rotation invalidates a refresh token as soon as it is used, and a replay of an invalidated token is read as a breach, so the authorization server revoked the active token and the grant had to be re-authorized.
solid answer
~50 sWith rotation, every successful refresh returns a **new** `refresh_token` and invalidates the one that was spent, while the authorization server keeps the relationship between them. That is what makes theft detectable: if a stolen copy and the honest client both refresh, one of them presents an invalidated token, and the server learns a copy exists. It cannot tell which party submitted it, so it revokes the **active** refresh token and both are cut off. Your boat's phone hit the honest-loss case - the response carrying the new token was lost to the dropped signal, so the phone still held the old one and replayed it on reconnect. The server saw a replay, did the only safe thing, and the berth-holder was asked to authorize again. RFC 9700 section 4.14.2 requires replay detection for refresh tokens issued to **public** clients, which may be met by rotation or by binding the token to a key the client holds.
code
http · 12 linesPOST /token HTTP/1.1
Host: as.marina.example
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=8xLOxBtZp8
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{"error":"invalid_grant"}go deeper
Recall that with rotation a refresh token is single-use: each refresh returns a new one and kills the old, so the same string cannot be redeemed twice.
Explain why the server keeps the link between old and new - a remembered, invalidated token is what makes a replay visible - and what it does when one shows up.
Volunteer the cost and the limits: a lost response signs an honest user out, concurrent refreshes collide, and a single unraced use by a thief is not caught at all.
Weigh detection against availability for the fleet you run. Single-use credentials fail in exactly the conditions production supplies, so decide per client class whether rotation or a key-bound token is the better bet.
## What rotation actually does Rotation is a rule about the refresh response, not about the token's contents. On every successful refresh: 1. the authorization server issues a **new** refresh token alongside the new access token; 2. it **invalidates** the refresh token that was just spent; 3. it **retains the relationship** between the two, so the old one is remembered as replaced rather than merely forgotten. Step 3 is the one that does the work. A forgotten token is simply unknown; a token remembered as replaced can be recognised when it comes back, and that recognition is the detection. ## Why that detects a stolen copy A refresh token can be copied, and a copy is indistinguishable from the original - both are the same string. What a thief cannot control is that the honest client also keeps refreshing. As RFC 9700 section 4.14.2 puts it: if a refresh token is compromised and then used by both the attacker and the legitimate client, one of them will present an invalidated refresh token, which informs the authorization server of the breach. The server **cannot determine which party submitted the invalid token**, so it revokes the active refresh token. Two honest limits belong in the answer: - detection depends on the race. A thief who uses the stolen token once, before the honest client's next refresh, is not revealed by rotation alone. - the response is blunt by necessity. Revoking the active token cuts off the attacker and the honest client together, because the server has no way to tell them apart. ## Your marina case, step by step 1. The phone, on a fading signal, POSTs its refresh token to the token endpoint. 2. The authorization server accepts it, invalidates it, and sends back a new access token and a **new refresh token**. 3. The response never lands - the boat is out of coverage by the time it is sent. 4. Hours later the phone reconnects still holding the **old** refresh token, and uses it. 5. The server sees an invalidated token presented again. From where it sits, this is exactly the shape of a replay. 6. It revokes the active refresh token, and the berth-holder is sent back through authorization. Nothing malfunctioned. This is the designed behaviour meeting a lossy network, and it is the cost side of rotation: the specification gives the server no way to distinguish a lost response from a theft, because from the wire the two are identical. ## Where the requirement comes from, and who it covers | point | what the specification says | |---|---| | who must have replay detection | refresh tokens issued to **public clients** | | acceptable means | rotation, or binding the token to a key the client proves it holds | | what a refresh token is bound to | the scope and resource servers the resource owner consented to | | on password change or sign-out | the server **MAY** revoke refresh tokens automatically | | after a long idle period | refresh tokens **SHOULD** expire after client inactivity | The scoping in the first row is the detail candidates flatten. RFC 9700 section 4.14.2 states the replay-detection requirement for refresh tokens issued to **public clients** - those unable to keep a secret. It is not a blanket rule for every client an authorization server serves, and an answer that promotes it to one is teaching a false certainty about a document that was careful here. The last two rows are worth the same care: one is a MAY and one is a SHOULD, and neither is a MUST. ## What rotation is and is not worth - **It is worth**: turning an undetectable copy into a detectable one, and putting a hard upper bound on how long a stolen refresh token stays usable once the honest client is still active. - **It is not worth**: protecting a client that has stopped refreshing entirely, since with no honest traffic there is no collision to notice. - **It costs**: an honest client can be signed out by a lost response, a crashed process between receiving and storing, or two copies of the same client refreshing at once. That last line is what a senior answer must volunteer. Rotation buys detection by making a refresh token single-use, and single-use credentials are fragile in exactly the conditions - flaky networks, concurrency, restarts - that production is made of. How a particular authorization server softens that is its own design decision; what the specification gives you is the detection and the reason it must be blunt.
- Does rotation catch a thief who uses the stolen refresh token only once?Not on its own. Detection comes from the collision between the attacker's use and the honest client's next refresh; a single use that wins the race leaves nothing invalidated to trip over. What rotation guarantees is that the stolen copy stops working the moment either party refreshes again, which bounds its useful life rather than preventing the first use.
- Why does the authorization server revoke the active refresh token instead of the one that was replayed?The replayed token is already invalid, so refusing it changes nothing. The one still usable is the active token, and since the server cannot tell whether the replay came from the attacker or the honest client, leaving it alive would mean leaving a thief's credential working. It revokes the thing that still has value.
- RFC 9700 says replay detection is required for which clients, and by what means?For refresh tokens issued to **public** clients - those that cannot keep a secret. The requirement may be met either by rotation or by issuing sender-constrained refresh tokens, which are bound to a key the client proves it holds. It is not stated as a blanket requirement covering every client an authorization server serves.
- What else does RFC 9700 say about a refresh token's life beyond rotation?That it must be bound to the scope and resource servers the resource owner consented to; that a server **MAY** revoke refresh tokens automatically when the resource owner signs out or changes a password; and that refresh tokens **SHOULD** expire after a period of client inactivity. The last two are a MAY and a SHOULD, not requirements.
A harbour office that voids your berth ticket each time you check in and hands you a fresh one. If a voided ticket ever turns up at the counter, the office knows there are two of them in circulation - but it has no way to tell which person at the desk is the boat owner, so it cancels the berth and asks for proof in person.
saying these in an interview costs you the question
- Says rotation always catches the thief, whatever they do
- Claims the server can tell the attacker's replay from the client's retry
- States RFC 9700's replay-detection requirement for all clients, not public ones
- Thinks a rotated refresh token stays usable until its own expiry
- Treats an honest client being signed out as a bug rather than the cost
- Believes rotation removes the need to expire refresh tokens at all