JSON Web Token

Tool

A signed string carrying who someone is and how long that claim lasts, presented on each request as proof of identity.

Why it exists

The web was built so that a server forgets you the moment a request finishes. Logging in once does not make the next request yours automatically, and opening a single screen fires dozens of requests, so identity has to be re-established every time. Sending the password again on each one is out of the question, so the pattern settled on handing out a temporary pass once the login succeeds.

The long-standing way to do that was to let the server remember. On login the server writes a record of the session into its own memory and hands the browser only the record number. When the browser returns with that number, the server looks it up and knows who is calling. With one server, this works fine.

The day Pagedeck went from one server to two, it stopped working. Users were getting logged out on every refresh. Requests that landed on server one found the record; requests that landed on server two found nothing. Theo traced it: each server kept its sessions in its own memory. One answer is to stand up a shared store that both servers read from. The other is to stop making servers remember at all. JWT is what the second answer looks like.

What it solves

It moves the remembering out of the server and into the pass itself. Instead of looking a caller up in a list, the server only has to confirm that what the pass says has not been tampered with.

The pass is one string joined by two dots, in three parts.

  1. Header — states how the pass was signed. The receiving side needs this to redo the same computation.
  2. Payload — who the holder is, what role they have, when the pass expires. Each field is called a claim: user 1024, role editor, expires in fifteen minutes.
  3. Signature — the result of running the first two parts through a key only the server knows.

When a request arrives, the server recomputes the first two parts with its key and compares the result against the third part. Change the role in the payload from editor to admin and the computed value no longer matches, so the request dies there. No storage is consulted, and any number of servers can do this as long as they hold the same key.

The first two parts are not locked. They are encoded for safe transport, not hidden, so anyone holding the pass can unfold and read every field in it. What the signature prevents is editing, not reading. Hiding the contents means adding encryption on top. This is why phone numbers and addresses do not belong in a payload.

The cost is just as concrete. Since the server keeps no record, there is no clean way to take a pass back once it has been handed out. Suspend an account and the passes already issued keep working until they expire. That's why the lifetime is kept short — fifteen minutes is typical — and paired with a separately stored refresh pass used to obtain a new one. The refresh pass is recorded on the server, so that one can be killed immediately.

Alternatives

There are three ways to hand out a pass.

  1. Sessions — the remember-on-the-server approach above. Because the record lives in one place, suspending an account cuts access instantly. In exchange, every request costs a lookup, and if that store goes down, every login goes down with it.
  2. Opaque tokens — the pass is a meaningless string, and whoever holds it asks the issuer who it belongs to. Nothing leaks and revocation is immediate, but each check adds a round trip.
  3. JWT — no round trip to verify and easy to spread across servers, at the price of slow revocation and readable contents.

Small internal tools with few users, where instant cutoff matters, tend to be happier with sessions. Systems split into many services that each need to verify on their own tend toward JWT. The same reasoning is why it shows up so often behind single sign-on (SSO), where one login covers several services: each service checks the pass in hand instead of calling a login server.

Nothing forces a single choice across a whole product, either. A common arrangement keeps sessions for the browser app, where the server controls the cookie anyway, and issues JWTs to the mobile clients and internal services that would otherwise need their own lookup path.

How it sounds at work

"If you get a 401, run a refresh once and retry the same request."

The pass expired, so fetch a new one and try again rather than bouncing the user to the login screen.

"Email in the payload is fine, but let's leave the phone number out."

Anyone holding the pass can read what's inside it, so sensitive fields don't go there.

"The account is suspended but they can still get in for fifteen minutes."

A pass already issued stays valid until it expires, and nothing stops it in the meantime.

From the month Pagedeck signed its first enterprise customer. Their security reviewer asked whether a departing employee's access could be cut immediately, and Theo's honest answer was up to fifteen minutes. That fell short of the contract. Dropping the lifetime to one minute came up first, but it multiplied refresh traffic roughly fifteenfold. The team settled on keeping a short list of suspended accounts and checking it only on the requests that matter.

This is also where authentication and authorization part ways. Confirming the pass is genuine is the first; deciding whether this person may delete this particular document is the second. A role written into the payload does not remove the need for the second check.

What people get wrong

The most common belief is that the contents are encrypted. A long run of unreadable characters certainly looks locked. It is encoding, not encryption, and the tools to reverse it are one search away — paste the pass in and the user id, the role, and the expiry come back in plain text. Left uncorrected, this assumption puts birthdates and addresses into payloads, and a single pass sitting in browser storage becomes a data leak.

The other is reading JWT as a finished login system. It's the term that appears most often in articles about authentication, which makes the leap easy. What the spec settles is the shape of the pass and how tampering gets detected. How passwords are stored, where the pass lives in the browser, how expiry and reissue are handled, what happens when a device is lost — all of that is still open. Treating a format choice as a completed design leaves those gaps to be discovered later, usually during an incident.

Easily confused with

TermWhat it definesHow it differs from JWT
OAuthThe procedure for delegating permissionIt specifies who asks whom, in what order, to obtain consent. It says nothing about the format of the pass that comes out, so a token from an OAuth flow may be a JWT or may be a meaningless string

Where to go next

Last updated 2026-09-16