Scaleup Infotech
Scaleup Infotech.
Back to Blog
Bug Fixes8 min read

Fix 'JsonWebTokenError / TokenExpiredError' in Node.js JWT Auth

Scaleup Infotech

Scaleup Infotech

Software & Marketing Agency

Mar 16, 2026
Fix 'JsonWebTokenError / TokenExpiredError' in Node.js JWT Auth
Node.jsJWTAuthentication

jsonwebtoken throws different errors for different problems — and treating them all as a generic 500 gives users a broken experience. Branch on the error type and add refresh tokens.

The Errors

TokenExpiredError: jwt expired | JsonWebTokenError: invalid signature | JsonWebTokenError: jwt malformed

Branch on the Error Type

javascript
const jwt = require("jsonwebtoken");

function verifyToken(req, res, next) {
  try {
    req.user = jwt.verify(req.token, process.env.JWT_SECRET);
    return next();
  } catch (err) {
    if (err.name === "TokenExpiredError") {
      return res.status(401).json({ code: "TOKEN_EXPIRED" });
    }
    return res.status(401).json({ code: "TOKEN_INVALID" });
  }
}

Add a Refresh Token Flow

Keep access tokens short-lived (15m) and issue a long-lived refresh token. When the client sees TOKEN_EXPIRED, it silently calls /refresh to get a new access token instead of logging the user out.

javascript
const accessToken = jwt.sign({ id }, SECRET, { expiresIn: "15m" });
const refreshToken = jwt.sign({ id }, REFRESH_SECRET, { expiresIn: "30d" });

Clock Skew

If tokens 'expire instantly' across servers, their clocks differ. Allow a small tolerance: jwt.verify(token, secret, { clockTolerance: 10 }).

Share this article:

Keep Reading

Ready to implement these ideas?

Work With Scaleup Infotech