Beta

Create a tenant

A new tenant starts with its own users, OAuth settings, audit history and logs. You are its first Tenant Admin.

BTL Admin

Refresh token theft

The copied access token in Token theft and replay stopped working within minutes. A refresh token is built to last. demo-refresh-token-4 is what lets the printer make your December calendar without you, and anyone else holding it could draw on the same authorization.

Why refresh tokens are worth stealing

A refresh token represents the whole authorization you gave a client, not one request to one API. It often lasts months, it needs no person to be present, and every use can produce a fresh access token with the grant's full scope. Current guidance calls refresh tokens an attractive target for exactly these reasons.

They are also kept for a long time, which gives an attacker time to find them. The printer's website keeps them, encrypted, in connection records in its database, as Server-rendered web applications described. The phone app keeps them on the device, where a careless backup or a compromised phone can expose them. A browser application that holds one puts it within reach of injected script.

What a thief can do with a copy depends on whether the client it belongs to can authenticate.

When the thief also needs the client

All domains, credentials, and tokens in these examples are fictional. Suppose an attacker gets far enough into the printer's systems to copy and decrypt its connection records, and tries one of the refresh tokens at the token endpoint:

POST /token HTTP/1.1
Host: auth.photos.example
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=demo-refresh-token-4
&client_id=photo-printer

The photo service issued that token to photo-printer, a confidential client. The original specification requires the authorization server to keep that binding and to check it, with client authentication, whenever the client can authenticate. This request carries no client credential, so the token endpoint answers invalid_client, and the refresh token alone is useless.

That is why the printer keeps its client credential somewhere other than its connection records, such as a secrets store, and why a private key held in a key management service helps further: it cannot be copied along with the database at all. A breach that reaches both turns into the incident Rotating client credentials described. The credential is revoked first, then the tokens issued with it are reviewed.

Racing under rotation

The printer's phone app, photo-printer-app, is a public client. It has no credential, so a copied refresh token is all a thief needs. For public clients, current guidance requires the authorization server either to bind refresh tokens to the client instance or to rotate them. With rotation, which The refresh token grant introduced, the server watches for one thing: a refresh token that has already been used, presented again.

Say the app holds demo-app-refresh-token-1, and a thief copies it from a phone backup. What happens next depends on who uses it first.

Who refreshes firstWhat the server seesOutcome
The thiefThe thief receives demo-app-refresh-token-2. Later, the app presents demo-app-refresh-token-1, which was already used.Reuse detected. The server revokes the family, including the thief's replacement. The thief keeps at most an access token until it expires, and you reconnect the app.
The appThe app receives demo-app-refresh-token-2. The thief then presents demo-app-refresh-token-1.Reuse detected. The family is revoked, so the thief gets nothing, and the app must reconnect too.
The thief, while the app stays unusedAn unbroken chain: token 1, then 2, then 3, each used once.Nothing looks wrong. The thief keeps rotating until the app returns, the family reaches its absolute lifetime, or something else ends the grant.

In the first two rows, the server cannot tell who presented the old token. It revokes everything, which stops the thief at the cost of one reconnection for you. The grace period that some servers allow, which Refresh tokens and rotation described, weakens these two rows slightly: a reuse within those few seconds is not treated as theft.

The third row is the gap that Refresh tokens and rotation anticipated when it capped every family with an absolute lifetime. Rotation notices theft only when both parties use the token, and an idle app uses nothing. The absolute lifetime ends the family on a fixed date however busily the thief rotates. The idle lifetime does not stop an active thief, but it does mean a token copied from an old phone or a forgotten backup is already dead by the time anyone finds it.

Sender-constraint closes the gap more directly. If the app's refresh tokens are bound to a key kept in the phone's secure hardware, a copy taken from a backup cannot be used at all, because the key was never in the backup. Advanced OAuth's DPoP lessons show how a public client binds its tokens this way.

Containing a theft

When the server detects reuse, or anyone suspects a theft, the response follows the same steps:

  1. Revoke the family, and the access tokens issued from the same grant where the server can reach them, as Token revocation described.
  2. Record a security event naming the client, the grant, the time, and the networks involved, but never the token values.
  3. Tell the person plainly, for example: "We disconnected Photo Printer from your photo account because one of its credentials was used in two places. Reconnect it if you still use it."
  4. Require reconnection. The client's next refresh fails with invalid_grant, and, as The refresh token grant described, it marks the connection as needing attention and asks you to connect again.

Detected reuse is not the only reason to end a family. Refresh tokens and rotation listed the others, from a password reset or account recovery to a suspended client or a leaked client credential. Each one is also a way of containing a theft that nobody has noticed yet: a person who resets their password because something felt wrong should not leave a thief's refresh token working behind them.

Reuse detection depends on legitimate clients never causing it. A client that runs two refreshes for the same connection at once presents a used token just as a thief would, and the server cannot tell the difference. The one-refresh-at-a-time rule from The refresh token grant keeps the signal meaningful, so that when reuse is reported, it can be treated as the security event it usually is.

Try it in the Lab

PUT IT INTO PRACTICE

Check your understanding

Try these questions before moving on. If an answer isn't right, use the feedback and try again.

0 of 2 answered correctly

Enable JavaScript to answer these questions and save progress in this browser.

QUESTION 1 OF 2An attacker copies refresh tokens from the printer website's database, but not its client credential. Can they refresh?

QUESTION 2 OF 2A thief copies the phone app's refresh token while the app goes unused for weeks, and keeps refreshing. Why might rotation not notice?

We value your privacy

We use cookies and similar technologies to enhance your browsing experience, and analytics to understand our traffic. By clicking "Allow All", you consent to optional analytics. Cookie Policy

Learn identity