{Inspector}

Developer Guide · 2026

JWT Expiration Time: What “expire in 15 minutes” Really Means

A JWT’s exp claim time-boxes the token on purpose: it limits how long a leaked token stays useful. But the exact second a token expires — and why it can appear to expire early — trips up most teams. This guide covers how the exp claim works, how libraries compute it, and how to check expiry yourself without a validation time bomb.

Benjamin Rotshtein

Written by Benjamin Rotshtein

Updated

What does the exp claim mean for a token’s lifetime?

The exp claim is a Unix timestamp in seconds telling services when the token stops being valid. Verify it on every request: if it’s past, the token is rejected even if the signature is perfect. It looks like the token expires early because the claim is absolute, not relative to the moment you read it.

The exp claim is seconds, not “15 minutes”

When your auth server says “token expires in 15 minutes,” it computes Math.floor(now/1000) + 900 and stores that integer in the exp claim. The number is always Unix time in seconds. There is no timezone, no human-readable date, no “lifetime” field — just an absolute timestamp. Any validator compares:

const current = Math.floor(Date.now() / 1000);
const expired = current >= payload.exp;   // true => reject the token

That single comparison is the whole rule. Everything confusing about JWT expiry is a detail layered on top of it: rounding, clock drift, and leeway.

The four time-related claims

ClaimWhat it meansRequired?
expExpiration time — the token is invalid after this timestampRecommended
iatIssued at — when the token was createdOptional
nbfNot before — token is invalid BEFORE this timestampRarely used
subSubject — the user or entity the token belongs toFor consumption

Why tokens look like they expire early

Three real causes, in order of frequency:

Leeway: the 30-60 second safety net

Libraries like jsonwebtoken, PyJWT, and JJWT accept a clockTolerance or leeway option. Validation then succeeds if current <= exp + leeway. Set it to zero on a single well-synced machine, and 30-60 seconds only when you run auth across containers or region-split services where clocks drift. Keep leeway well below the token lifetime, otherwise a near-expired token can “leeway” its way back into validity.

Check expiry the way a validator does

The cleanest way to understand why a token is being rejected is to decode it and compare exp against the current time yourself. A JWT decoder shows the exact expiration instant alongside the rest of the claims, so a “your session expired” error becomes “this token died 4 minutes ago at 14:03,” which tells you whether the client is reusing a stale token or the server minted one too short.

Held for too long? Rotate, not extend

The day your team decides 15 minutes feels too short and bumps it to 24 hours, stop. Longer access tokens mean bigger blast radius if one leaks. The maintainable pattern is a short-lived access JWT (5-15 minutes) backed by a revocable opaque refresh token (days-weeks). You get instant revocation at the refresh layer and a small window of exposure at the access layer — the best of both sides.

Frequently asked questions

What does JWT expiration (exp) actually check?

The exp claim is a NumericDate — the number of seconds since the Unix epoch (1970-01-01T00:00:00Z), ignoring leap seconds. A token is considered expired when the current time in seconds is equal to or greater than exp. Decoding a token and reading exp directly is what a token inspector does instead of trusting an opaque 'valid/expired' verdict.

Why does my JWT expire a few seconds early?

Because exp is compared as whole seconds, and any milli- or microsecond captured between the server minting the token and your client validating it pushes the current time past exp. It is normal and harmless. Libraries add an optional 'leeway' (usually 30-60 seconds) to absorb clock drift and this rounding.

What is JWT leeway and when should I add it?

Leeway is a tolerance window (in seconds) added to the current time when comparing nbf and exp, to tolerate small clock skew between different servers. On a single machine it can be 0. Across distributed services or containers with drifting clocks, 30-60 seconds is common. Never use leeway larger than your minimum token lifetime — one can swallow the other.

How to compute time until JWT expiry?

Subtract current Unix time from exp: timeLeftSeconds = exp - Math.floor(Date.now()/1000). If the result is positive the token is still valid; if negative it is expired. For displaying 'expires in', convert the remaining seconds to minutes or hours.

Can I refresh a JWT when it expires?

Yes — the standard pattern is a separate refresh token (opaque, stored server-side) that is exchanged for a new short-lived access JWT. The refresh token carries a longer exp. This gives short-lived access tokens (lower leak impact) with a revocable long-lived session.

Check a token’s real expiry — 100% in your browser

Decode any JWT and read its exp, iat and nbf claims instantly, without the token ever leaving your machine. Verify exactly when it dies — not just a vague “valid/expired” verdict.

Related guides