JWT Expiration and Refresh Tokens Explained

A JWT doesn't expire on its own — you bake an expiration time into the token when you create it, and anything that receives the token is responsible for checking it. Here's how that works and why refresh tokens exist.

The exp claim

The exp claim is a Unix timestamp (seconds since epoch) after which the token must be rejected:

{
  "sub": "user_123",
  "iat": 1718400000,
  "exp": 1718403600
}

In this example the token was issued at iat and expires one hour later (iat + 3600). Any server receiving this token should verify the current time is before exp. There is no revocation — once issued, the token is valid until it expires (unless you build a denylist).

Paste any JWT into the JWT decoder to instantly see its exp and iat values as human-readable timestamps.

Why short-lived access tokens?

Because you can't revoke a JWT easily, you keep them short-lived (minutes to an hour). If one is stolen, the damage window is limited. Typical pattern:

  • Access token: 15–60 minutes, sent with every request.
  • Refresh token: days to weeks, stored securely, used only to get new access tokens.

The refresh flow

Client → POST /auth/login
Server → { access_token (15min), refresh_token (30 days) }

...15 minutes pass...

Client → POST /auth/refresh  { refresh_token }
Server → { new access_token (15min) }

The refresh token is usually opaque (a random string in a database) so the server can revoke it — just delete the row. The access token stays a signed JWT.

What makes a refresh token revocable

Unlike JWTs, a refresh token only has value if the server recognizes it. Storing refresh tokens in your database means you can:

  • Log out a user by deleting their refresh token.
  • Detect reuse (if a refresh token is used twice, someone has it who shouldn't).
  • Enforce single-device or multi-device policies.

Common mistakes

  • No exp claim — the token is valid forever. Always set an expiration.
  • Too-long access tokens — a 7-day access token defeats the point of short-lived tokens.
  • Storing refresh tokens in localStorage — accessible to JavaScript; prefer httpOnly cookies.
  • Not validating exp on the server — client-side expiry checks can be bypassed.

See what are JWT claims for the full list of standard claims, and what is a JWT for the basics of how JWTs are structured.

Got a config file to check?

Open the config toolkit →