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

Token theft and replay

The attacks so far went after the authorization code, the credential on its way to becoming a token. Once the printer holds an access token, the question changes. As a bearer token, it works for whoever presents it, and the printer sends it to the photo API with every request, which gives a copy many chances to escape.

Where access tokens escape

Tokens rarely leak because someone broke the cryptography. They leak because a copy ends up somewhere it was never meant to be.

RouteHow a copy gets out
LogsThe printer records the full request when a photo API call fails, Authorization header included, or a debugging proxy records every header it sees.
URLsA developer puts the token in a query parameter for convenience. The address then lands in browser history, server logs, and Referer headers, which is why Using access tokens kept tokens in the header.
Browser storageA browser application such as the photo editor keeps tokens where injected script can reach them, as Browser applications described.
ProxiesA proxy that ends the TLS connection in front of an API sees every request in plain form, and its logs or caches can keep what it sees.
A compromised APIAn attacker who controls the photo API, or can only read its logs, collects every token that clients present to it.
A counterfeit APIA client that learns an API's address at run time, for example from a setting a person types in, can be pointed at a server built to collect tokens.
A misdirected requestA client follows an address from a response, such as a link to the next page of results on another host, and attaches the token without checking where it is going.

In the last three, the token reaches the wrong hands through the front door, in an ordinary API request that the client chose to send. Clients should check where their tokens go, as Using access tokens described, but experience shows many do not. That is why the most dependable limits on a copy are set by the authorization server and checked by the API, instead of depending on every client behaving well.

Replaying a copied token

All domains and tokens in these examples are fictional. Suppose the printer's error logging captured a request at 09:02 UTC, and someone with access to the logs copied the token. At 09:03, from their own laptop, they send this:

GET /albums/42/photos HTTP/1.1
Host: api.photos.example
Authorization: Bearer eyJhbGciOiJFUzI1NiIsImtpZCI6InBob3Rvcy0yMDI2LTA5IiwidHlwIjoiYXQrand0In0...

The token is the JWT access token from Token formats and validation, shortened here for display. Nothing distinguishes this request from one the printer would make. The signature verifies, the issuer and audience are right, the token has not expired, and photos.read covers the operation, so the photo API returns your album. Replaying a token means exactly this: presenting a copy as if you were the party it was issued to, and nothing in a bearer token tells the API who is presenting it.

What limits the copy is written in the token itself:

"aud": "https://api.photos.example",
"scope": "photos.read",
"exp": 1790845800

exp is 09:10:00 UTC on 1 October 2026, seven minutes after the replay. Until then, the copy works. Revoking it helps only at APIs that check with the authorization server. An API that validates the JWT locally keeps accepting it until it expires, as Token revocation explained.

The copy also does only what the token allows. With photos.read, the attacker cannot delete your photos. With an audience of https://api.photos.example, the sharing API at https://share.photos.example refuses it: the token was not issued for that API, as Scopes and audiences explained.

Limiting the damage

No single measure stops a copied bearer token. Several together shrink what a copy is worth.

MeasureWhat it limits
Short lifetimesHow long a copy works. Refresh tokens are what make lifetimes of minutes practical.
Audience restrictionWhere a copy works: one API, not every API that trusts the issuer.
Minimal scopeWhat a copy can do: read photos, not delete them.
TLS on every connectionCopies taken from the network in transit.
Keeping tokens out of URLs and logsThe most common leaks. Logging code removes Authorization headers and token parameters before anything is written.
DetectionHow long a theft goes unnoticed. Signs include requests from unexpected networks for a client, unusual request rates, and attempts to use tokens that were already revoked.

Current guidance spells out several of these. Access tokens should carry the minimum privileges the use case needs and should be restricted to a specific API, or a small set of them, and every API must refuse a token that was not meant for it. Clients must not send access tokens in a URL query parameter, and TLS is recommended all the way from the client to the API. It also says an API must treat the tokens it receives like other sensitive secrets, never storing or passing them on in plain form.

Binding a token to its holder

All of those measures limit a copy. None of them makes a copy useless, because a bearer token is complete by itself. A sender-constrained token is not. It is bound to a key that the client holds, and the API accepts it only from a sender who can prove possession of that key.

The idea works like this. The client generates a key pair and keeps the private key. When the authorization server issues the token, it records which key the token belongs to. In a JWT access token, that record is a confirmation claim carrying a fingerprint of the public key, or of a certificate that contains it. With each API request, the client sends a fresh proof made with the private key, or proves possession of it through its TLS connection. The API checks that the proof matches the key named in the token. Someone who copies the token from a log does not have the private key, so the copy fails.

Binding protects against copies, not against an attacker who controls the client. Script injected into the photo editor can use the editor's key while the page is open, just as it can use the token. If the key is kept where it cannot be exported, though, the key itself cannot travel to the attacker's own machine the way a copied token can. The script can still prepare proofs in advance while the page is open, which is why servers tie each proof to one access token and can also require a fresh value of their own in it.

Current guidance says authorization servers and APIs should use sender-constrained access tokens. Advanced OAuth covers the two standard mechanisms, DPoP and mutual TLS, with their proofs and the checks at each end.

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 2Someone copies a bearer access token from a log and replays it from their own laptop. What does the API see?

QUESTION 2 OF 2The photo service now issues sender-constrained access tokens to the phone app. Someone copies one from a debugging log and replays it from their own laptop. What happens?

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