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.
| Route | How a copy gets out |
|---|---|
| Logs | The printer records the full request when a photo API call fails, Authorization header included, or a debugging proxy records every header it sees. |
| URLs | A 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 storage | A browser application such as the photo editor keeps tokens where injected script can reach them, as Browser applications described. |
| Proxies | A 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 API | An attacker who controls the photo API, or can only read its logs, collects every token that clients present to it. |
| A counterfeit API | A 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 request | A 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.
| Measure | What it limits |
|---|---|
| Short lifetimes | How long a copy works. Refresh tokens are what make lifetimes of minutes practical. |
| Audience restriction | Where a copy works: one API, not every API that trusts the issuer. |
| Minimal scope | What a copy can do: read photos, not delete them. |
| TLS on every connection | Copies taken from the network in transit. |
| Keeping tokens out of URLs and logs | The most common leaks. Logging code removes Authorization headers and token parameters before anything is written. |
| Detection | How 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.