Free & open · no paywall, ever

IntegrAuth Academy

Identity, security and practical AI — free, from zero. Byte-sized lessons, real diagrams, hands-on labs, zero fluff. Two programs, each with its own exam and certificate.

20 tracks 241 lessons 242 hands-on labs 230+ diagrams 100% free

English is hard? Your browser can translate this page into Tamil, Telugu, Kannada, Malayalam or Hindi. Tech words stay in English so you learn the real names.

How?
  • Chrome on phone: ⋮ menu → Translate
  • Chrome on computer: right-click → Translate to …
  • Edge: the translate icon in the address bar
Identity & API Security Track 3 · Token Security
0/166 lessons read
TOKEN SECURITY · LESSON 4

Stolen-token defenses I — revoke, expire, step up

You press "sign out everywhere". Your session and refresh tokens die at once. But an access token a thief already copied keeps working until it expires. Your goal: name four server checks that refuse a stolen access token.

Key points
  • A signed access token works until it expires, even if stolen.
  • A revocation marker refuses every token issued before a cut-off time.
  • Freshness and method checks refuse old or weak tokens for risky actions.
  • The API is the control. The screen is only a convenience.

Why a stolen access token is stubborn

Many access tokens are self-contained JWTs. The API checks the signature and trusts the token without calling the IdP. That is fast. But nobody can take back copies already out there. The thief's copy works until the token's exp (its expiry time). Three credentials matter here. A session cookie lives in the browser. A refresh token makes new access tokens. An access token opens the API on every call. The server can cancel the session and the refresh token at once. It cannot cancel an access token. That one works until exp.

Defense 1: a revocation marker

This is the one defense that truly stops a live stolen token. When you sign out everywhere, the API writes a revocation marker. It is a cut-off time. It means "everything issued before now is dead".

On every call, right after the signature check, the API compares two times. One is the token's iat (issued-at time). The other is the cut-off. If iat is at or before the cut-off, the API refuses the token with token_revoked. A fresh login makes a token after the cut-off. So the gate stays open for the real user and shut for the thief.

Think of it like…

A hotel front desk. A guest loses a key card. The desk writes: "Every card made before 9 pm is dead." Every door lock checks this note. A new card made after 9 pm works. The old card does not.

MayaAttackerResource APIRevoke store1 · sign out everywhere2 · write cut-off = now4 · call (Bearer: stolen token)5 · read cut-off3 · stored6 · cut-off epoch8 · ✗ 401 token_revoked7 · token.iat ≤ cut-off?
Figure — Refused in mid-life. The same unexpired token goes from accepted to refused as soon as the marker exists. The API checks it on every call.

Defenses 2 and 3: shrink the window

⏱️ Freshness gate

A high-value action needs a token made seconds ago. The API checks now − iat. If it is older than the window (say 120 seconds), the API refuses with token_too_old. A copy taken an hour ago fails, even if it has not expired.

🔐 Method check (step-up)

Some actions need a second factor. The API checks that the token shows MFA: the amr claim (the login methods used) includes mfa. This is MFA. If it is missing, the API answers 401 insufficient_user_authentication. The client then asks the user for fresh proof. This is step-up.

ClientResource APIIdP1 · call (Bearer: password-only token)3 · step up: complete a 2nd factor5 · retry → ✓ 200 accepted2 · ✗ 401 insufficient_user_auth (RFC 9470)4 · new token, amr=mfaamr has mfa?
Figure — Prove the method. A logged-in token is not enough. The API wants the token to show a second factor. See step-up & assurance.

Defense 4: "sudo" re-authentication

On a laptop, the command sudo asks for your password again before a risky change. An API can do the same. It refuses tokens that came from a refresh, because no person was there. It also needs auth_time (when the user last signed in) to be recent. This is about when you proved yourself, not how.

Watch out

"I did MFA earlier" is not the same as "this token shows MFA now". A silent refresh can make a new access token with no new MFA. Never assume. Check the live token. If it is not enough, send the user through a real step-up.

Why it matters

All of these gates live on the server. A thief still holds a working token between calls. The next lesson makes the copy itself useless.

Go deeper: standards behind the gates

The standard way to cancel a token is the revocation endpoint (RFC 7009). It works well for refresh tokens and for opaque tokens. A self-contained JWT needs the extra gates above.

The names token_revoked and token_too_old are examples from this course. They are not standard error codes. A real API picks its own name or answers a plain 401 invalid_token.

The error insufficient_user_authentication comes from RFC 9470. It tells the client that the token does not show the needed method, usually mfa in amr.

🧪 Interactive lab — enable JavaScript to play with this one.

🧪 Try it free

Audit your app's logout and revocation habits with Logout Check.