JWT Token Expired: 9 Quick Fixes for Real 401 Errors cover image
Prateek Zare

Written by Prateek Zare

Software Developer with ML and Data Expertise, 8+ years of experience

Last updated
Developer Tools

JWT Token Expired: 9 Quick Fixes for Real 401 Errors

A JWT token expired error means the server compared the exp claim with its own clock and found the token too old. Most of the time that is the whole story. When the token looks fresh and the error persists, the cause sits in one of eight other places, and this guide shows you how to find it in about a minute.

Fast diagnosisDecode the token and read three numbers: iat, nbf and exp. They are seconds since 1 January 1970 UTC. Compare each with the current time on the machine that rejected the token. A past exp means refresh. A future exp with a rejection points to clock skew, wrong units, nbf, audience or issuer.

Step one: read the claims of the token behind the JWT token expired error

A JSON Web Token has three parts separated by dots: header, payload and signature. The first two are base64url encoded JSON, not encrypted, so anyone holding the token can read them. You need no key for that. Here is a real example I generated, with a lifetime of 15 minutes.

Sample token behind a JWT token expired error

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyXzQyIiwiYXVkIjoiYXBpLmV4YW1wbGUuY29tIiwiaWF0IjoxNzY3MjI1NjAwLCJleHAiOjE3NjcyMjY1MDAsInNjb3BlIjoicmVhZDpvcmRlcnMifQ.SOb9ntWowAoJACZ6_lINwtUOP2AnEFTsB-i3n227PxA

Decoded payload for the JWT token expired check

{
  "iss": "https://auth.example.com",
  "sub": "user_42",
  "aud": "api.example.com",
  "iat": 1767225600,
  "exp": 1767226500,
  "scope": "read:orders"
}
Reading each claim in the sample when a JWT token expired error appears
ClaimValueWhat it tells you
iat1767225600Issued at 1 January 2026, 00:00:00 UTC
exp1767226500Expires 900 seconds later, at 00:15:00 UTC
audapi.example.comOnly this API should accept the token
isshttps://auth.example.comOnly this issuer should be trusted
subuser_42The user the token is about

The JWT Decoder does this split for you, labels each standard claim and shows a valid or expired badge computed from your local clock. Paste the token with or without the Bearer prefix.

Nine causes behind an expired or invalid token

Error wording for a JWT token expired failure differs between libraries. Node packages raise names such as TokenExpiredError, and PyJWT raises ExpiredSignatureError. The table maps what you see to the usual cause and the fix.

JWT token expired symptom, cause and fix
SymptomLikely causeFix
Expired error, exp is in the pastThe token is simply oldRequest a new access token with the refresh token or sign in again
Expired error, exp is in the futureClock skew between serversSync clocks with NTP and allow a small leeway
Not active yet, right after loginnbf or iat is ahead of the validator clockFix clock skew or issue nbf slightly in the past
Token never expiresexp written in millisecondsUse whole seconds
Malformed or wrong number of segmentsQuotes, spaces, line breaks or a Bearer prefix in the valueStrip the extras so only three parts remain
Invalid signatureWrong secret or key, wrong algorithm, key rotationVerify with the issuer key in a server library, check the kid header
Invalid audienceaud differs from what the API expectsAlign aud with the API configuration
Invalid issueriss differs from the configured issuerMatch the exact issuer string, including the trailing slash
Works in a decoder, rejected by the APIDecoding does not verify or check revocationVerify the signature and test the revocation list on the server

Paste the token behind your JWT token expired error, read exp, nbf and aud at a glance, and see whether it has expired by your own clock. The token never leaves your browser.

Open the JWT Decoder

Clock skew: rejected on a fresh token

Two machines rarely agree to the second. If your validator runs 40 seconds ahead of the issuer, it declares a token dead 40 seconds early. Take the sample token with exp 1767226500.

JWT token expired effect of a validator clock running 40 seconds fast
ItemValue
Issued at00:00:00 UTC
exp00:15:00 UTC
Rejected from, real time00:14:20 UTC
Usable lifetime860 seconds
Lifetime lost40 seconds, 4.4 percent

On a 15 minute token that loss is a nuisance. On a token that lasts 60 seconds it can mean the token is dead on arrival. Most libraries offer a leeway or clock tolerance option, often set to something like 30 or 60 seconds. Use a small value and fix the clocks as well. A large leeway weakens expiry.

The milliseconds mistake

JavaScript time is in milliseconds, JWT time is in seconds. Developers who write Date.now() straight into exp create tokens that appear to last for millennia. Count the digits.

JWT token expired check: telling seconds from milliseconds
DigitsUnitExampleReads as
10Seconds, correct for JWT17672265001 January 2026, 00:15:00 UTC
13Milliseconds, wrong for JWT1767226500000Year 57971 when read as seconds

The reverse problem exists too. If a client multiplies exp by 1000 for a JavaScript date, a token with a 13 digit value ends up unreadable. Paste values into the Unix Timestamp Converter when you need to see the date behind a number.

Decoding is not trusting when a JWT token expired

Reading a payload proves nothing about who wrote it. Anyone can craft a token with any claims. The signature is what binds the claims to the issuer, and only a server holding the right key can check it. Never paste a secret key into a web page.

A diagnostic order that saves time

  1. Confirm the structureThe value must have three parts, or two for an unsigned token. If it does not, the problem is in how your client stores or sends it.
  2. Read exp, nbf and iatConvert each to a date. Check the digit count first, so you spot milliseconds.
  3. Compare with the validator clock that said JWT token expiredRun the date command on the server that rejected the token. A difference of more than a few seconds explains many intermittent failures.
  4. Check aud and issCompare them character by character with the API settings. A trailing slash is enough to fail.
  5. Check alg and kid in the headerThe algorithm must match what the server accepts. A kid that points to a rotated key explains a signature failure that started suddenly.
  6. Verify on the serverUse your server side library with the right key. Only that step proves the token is genuine and not revoked.
Quick checks for a JWT token expired error before you open a ticket

Stop the error from reaching users

Fixing the cause is half the job. The other half is making sure a JWT token expired response does not become a visible failure. A short lived access token is supposed to expire, so the client should expect it and recover quietly.

Fragile client on an expired response

  • Sends the same token until the server says no
  • Shows an error page on the first 401
  • Stores expiry as local time or in milliseconds
  • Retries the failed request without a new token

Resilient client

  • Reads exp and refreshes shortly before it passes
  • Catches one 401, refreshes once, then repeats the request
  • Stores expiry as seconds since 1970 UTC
  • Signs the user out only if the refresh itself fails

Refresh a little early to avoid a JWT token expired error

function needsRefresh(token, marginSeconds) {
  var payload = JSON.parse(atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')));
  var now = Math.floor(Date.now() / 1000);
  return payload.exp - now < marginSeconds;
}
// refresh when fewer than 60 seconds remain
if (needsRefresh(accessToken, 60)) { accessToken = await refresh(); }

A margin of 60 seconds protects against small clock differences and slow networks. It also means the user never sees the moment of expiry. Keep the refresh call itself behind a lock, so ten parallel requests trigger one refresh and not ten.

Token types and their usual job when a JWT token expired
TokenTypical lifetimeWhere it goesIf it expires
Access tokenMinutesSent with each API callRefresh silently
Refresh tokenDays or weeksSent only to the token endpointAsk the user to sign in
ID tokenMinutesRead by the client once after loginNot used for API calls

Lifetimes are policy, not law. Your identity provider sets them, and the right values depend on how much damage a stolen token could do. The point is the pattern: short for access, longer for refresh, and a clear path from one to the other.

If you want to see how a segment becomes text, the Base64 Encoder and Decoder shows the standard alphabet, while JWT swaps plus and slash for hyphen and underscore. To understand how a keyed signature is built, try the HMAC Generator.

A token shows exp 1767226500 and the server rejects it at 00:14:30 UTC with a JWT token expired error. What is the most likely cause?

The token should be good until 00:15:00 UTC. A rejection 30 seconds early points to clock skew on the validating machine.

Questions people ask about a JWT token expired error

How do I check if a JWT token expired?

Decode the payload, read the exp claim and compare it with the current Unix time in seconds. If exp is smaller than now, the token is expired.

Can I decode a JWT without the secret key?

Yes. The header and payload are base64url encoded, not encrypted. Only verifying the signature needs the key.

Why is my JWT invalid even though the JWT token expired check passes?

Check the signature key, algorithm, aud and iss values, nbf and clock skew. Any one of them can make a valid looking token fail.

What is the difference between exp, nbf and iat?

Exp is the time after which the token must be rejected, nbf is the time before which it must not be accepted, and iat is when it was issued. All three are numbers of seconds since 1970 UTC.

Should I extend the lifetime to stop the JWT token expired errors?

No. Short lived access tokens limit damage if one leaks. Use a refresh token to get new ones, and fix the underlying clock or unit problem.

Is it safe to paste a JWT into an online decoder?

Treat a live token like a password. A decoder that runs in your browser and makes no network request limits the risk, but prefer test tokens for anything sensitive.

Sources: RFC 7519, JSON Web Token (JWT)