DevTools Hub

Search tools

Search for a developer tool

How to Check if a JWT Is Expired

Part of the JWT Toolkit
Pattern
exp * 1000 < Date.now()

true means expired — exp is in seconds, Date.now() is in milliseconds

Explanation

A JWT's expiration lives in its exp claim — see the full JWT Claims Reference — as a NumericDate: an integer count of seconds since the Unix epoch. Checking expiration is just decoding the payload and comparing that number to the current time. The catch is that exp is in seconds and JavaScript's Date.now() is in milliseconds — miss that conversion and every check is wrong by a factor of 1000.

If the token also has an nbf (not-before) claim, check that first: a token can be not yet valid, which is a different state from expired and needs its own handling rather than falling through to an expiration check that assumes the token has already started its valid window.

And however the check comes out, it only tells you about time — it says nothing about whether the token is genuine. A token past its exp is worthless regardless of its signature, but a token that isn't expired could still be forged; the expiration check and signature verification are separate questions, and only JWT Inspector or JWT Signature Verifier answer the second one.

Valid examples

  • const expired = decoded.exp * 1000 < Date.now();

    The correct check: convert exp from seconds to milliseconds before comparing to Date.now().

  • if (decoded.nbf && decoded.nbf * 1000 > Date.now()) { /* not yet valid */ }

    Check nbf first if present — a token can be "not yet valid", which isn't the same thing as expired.

  • const neverExpires = decoded.exp === undefined;

    No exp claim at all means the token has no built-in expiration — don't treat a missing exp as expired.

Invalid examples

  • decoded.exp < Date.now()

    Comparing exp (seconds) directly to Date.now() (milliseconds) — a token that's actually still valid for hours will incorrectly read as already expired.

  • if (!decoded.exp) { markExpired(); }

    Treating a missing exp claim as expired — RFC 7519 says no exp means no built-in expiration, not that the token has already expired.

  • const trusted = !expired;

    Trusting a token just because it isn't expired — expiration doesn't verify the signature, so an unexpired but forged token would pass this check too.

Try it now