How to fix Error: JsonWebTokenError: invalid token in Node.js

Node.jsINTERMEDIATEMEDIUMUpdated Dec 9, 2025· 165 views

This error occurs when the jsonwebtoken library fails to parse or decode a JWT token during verification. The token structure is malformed, corrupted, or contains invalid encoding that prevents successful parsing.

Quick fix

Fixes JsonWebTokenError

const jwt = require('jsonwebtoken');

function verifyToken(token) {
  // Check for null, undefined, or empty string
  if (!token || typeof token !== 'string') {
    throw new Error('Token must be a non-empty string');
  }
  
  console.log('Token value:', token);
  console.log('Token length:', token.length);
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    return decoded;
  } catch (error) {
    console.error('JWT verification failed:', error.message);
    throw error;
  }
}
  1. Verify token is a non-empty string
  2. Check token structure has three parts
  3. Strip authentication scheme prefixes
  4. Remove whitespace and newlines
node.js — error
const jwt = require('jsonwebtoken');
function verifyToken(token) {
// Check for null, undefined, or empty string
if (!token || typeof token !== 'string') {
throw new Error('Token must be a non-empty string');
}
console.log('Token value:', token);
console.log('Token length:', token.length);
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
return decoded;
} catch (error) {
console.error('JWT verification failed:', error.message);
throw error;
}
}
Error: JsonWebTokenError: invalid token

What this error means

The "JsonWebTokenError: invalid token" error is thrown by the Node.js jsonwebtoken library when it cannot successfully parse or decode a JWT (JSON Web Token) during the verification process. This is a structural parsing failure, meaning the library encountered a token that doesn't meet the basic format requirements of a valid JWT. A properly formatted JWT must consist of exactly three Base64URL-encoded components separated by dots: header.payload.signature. When jwt.verify() receives a token that doesn't match this structure or contains invalid encoding, it throws this error to indicate the token cannot be decoded. This error is distinct from "invalid signature" (cryptographic verification failure) and "TokenExpiredError" (expired but valid token). The "invalid token" error specifically means the token's structure or encoding is fundamentally broken, preventing even basic parsing before any signature verification or expiration checks can occur.

Typical symptoms

  • JWT verification fails with "JsonWebTokenError: invalid token" message
  • Authentication middleware rejects all incoming requests
  • Token validation returns null or undefined instead of decoded payload
  • API endpoints return 401 Unauthorized despite having a token
  • Console logs show "invalid token" errors during jwt.verify() calls
  • Frontend authentication flow breaks at token verification step

Common causes

  1. Token passed to jwt.verify() is null, undefined, or empty string
  2. Token does not have exactly three dot-separated components (header.payload.signature)
  3. Token contains "Bearer " or "JWT " prefix that was not stripped before verification
  4. Token string contains newlines, whitespace, or line breaks
  5. Token uses invalid Base64URL encoding (wrong characters or padding)
  6. Token was corrupted during transmission (truncated, modified, or concatenated)
  7. Token extraction from Authorization header includes extra characters
  8. Token is actually a different type of credential (API key, session ID, etc.)
  9. Token string was incorrectly stored with quotes or escape characters
  10. Token payload or header contains invalid JSON that cannot be parsed

How to fix "Error: JsonWebTokenError: invalid token"

1Verify token is a non-empty string

Before calling jwt.verify(), check that the token is a valid string:

javascript
const jwt = require('jsonwebtoken');

function verifyToken(token) {
  // Check for null, undefined, or empty string
  if (!token || typeof token !== 'string') {
    throw new Error('Token must be a non-empty string');
  }
  
  console.log('Token value:', token);
  console.log('Token length:', token.length);
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    return decoded;
  } catch (error) {
    console.error('JWT verification failed:', error.message);
    throw error;
  }
}

This validates the token type and logs its value for debugging.

2Check token structure has three parts

Validate that the token has exactly three dot-separated components:

javascript
function validateTokenStructure(token) {
  const parts = token.split('.');
  
  if (parts.length !== 3) {
    console.error(`Invalid JWT structure: expected 3 parts, got ${parts.length}`);
    console.error('Token parts:', parts);
    throw new Error('JWT must have exactly three dot-separated parts (header.payload.signature)');
  }
  
  // Check each part is non-empty
  if (parts.some(part => !part || part.length === 0)) {
    throw new Error('JWT parts cannot be empty');
  }
  
  console.log('Token structure valid: header, payload, signature present');
  return true;
}

// Use before verification
const token = req.headers.authorization?.replace('Bearer ', '');
validateTokenStructure(token);
const decoded = jwt.verify(token, process.env.JWT_SECRET);

This ensures the basic JWT format is correct.

3Strip authentication scheme prefixes

Remove "Bearer " or "JWT " prefixes from the Authorization header:

javascript
function extractToken(authHeader) {
  if (!authHeader) {
    throw new Error('Authorization header missing');
  }
  
  // Handle different authentication schemes
  let token = authHeader;
  
  if (authHeader.startsWith('Bearer ')) {
    token = authHeader.substring(7); // Remove 'Bearer '
  } else if (authHeader.startsWith('JWT ')) {
    token = authHeader.substring(4); // Remove 'JWT '
  }
  
  // Trim whitespace
  token = token.trim();
  
  console.log('Extracted token:', token.substring(0, 20) + '...');
  return token;
}

// Express middleware example
app.use((req, res, next) => {
  try {
    const authHeader = req.headers.authorization;
    const token = extractToken(authHeader);
    req.user = jwt.verify(token, process.env.JWT_SECRET);
    next();
  } catch (error) {
    res.status(401).json({ error: 'Authentication failed', message: error.message });
  }
});

This handles common prefix formats in Authorization headers.

4Remove whitespace and newlines

Ensure the token is a single-line string without any whitespace:

javascript
function sanitizeToken(token) {
  // Remove all whitespace, newlines, and carriage returns
  const sanitized = token
    .replace(/\s+/g, '') // Remove all whitespace
    .replace(/\n/g, '')  // Remove newlines
    .replace(/\r/g, '')  // Remove carriage returns
    .trim();
  
  console.log('Original length:', token.length);
  console.log('Sanitized length:', sanitized.length);
  
  if (token.length !== sanitized.length) {
    console.warn('Token contained whitespace characters');
  }
  
  return sanitized;
}

// Apply sanitization
const rawToken = req.headers.authorization?.replace('Bearer ', '');
const cleanToken = sanitizeToken(rawToken);
const decoded = jwt.verify(cleanToken, process.env.JWT_SECRET);

This removes formatting characters that can break JWT parsing.

5Validate token was generated correctly

Verify the token generation process is creating valid JWTs:

javascript
const jwt = require('jsonwebtoken');

// Token generation
function generateToken(userId) {
  const payload = {
    userId: userId,
    iat: Math.floor(Date.now() / 1000), // Issued at
  };
  
  const secret = process.env.JWT_SECRET;
  
  if (!secret) {
    throw new Error('JWT_SECRET environment variable not set');
  }
  
  const token = jwt.sign(payload, secret, {
    expiresIn: '24h',
    algorithm: 'HS256',
  });
  
  console.log('Generated token:', token.substring(0, 30) + '...');
  console.log('Token parts:', token.split('.').length);
  
  // Immediately verify the generated token
  try {
    const verified = jwt.verify(token, secret);
    console.log('Token generation verified successfully');
  } catch (error) {
    console.error('Generated token is invalid:', error.message);
  }
  
  return token;
}

// Usage
const token = generateToken('user123');
res.json({ token });

This ensures tokens are created correctly before they're sent to clients.

6Test token on jwt.io debugger

Use the jwt.io debugger to inspect and validate your token:

1. Copy the token string from your logs or browser
2. Go to https://jwt.io/
3. Paste the token in the "Encoded" section
4. Check if the debugger shows "Invalid Token" in red
5. If invalid, inspect which part is causing issues:
- "Invalid signature" means the token structure is valid but signature doesn't match
- "Invalid token" means the structure itself is malformed
6. Verify the decoded header and payload appear correctly

javascript
// Debug token components
function debugToken(token) {
  const parts = token.split('.');
  
  console.log('Number of parts:', parts.length);
  
  parts.forEach((part, index) => {
    const names = ['Header', 'Payload', 'Signature'];
    console.log(`\n${names[index]}:`);
    console.log('Raw:', part.substring(0, 50) + '...');
    console.log('Length:', part.length);
    
    if (index < 2) { // Don't try to decode signature
      try {
        const decoded = Buffer.from(part, 'base64url').toString('utf8');
        console.log('Decoded:', decoded);
      } catch (error) {
        console.error('Failed to decode:', error.message);
      }
    }
  });
}

// Usage
debugToken(token);

This manual inspection helps identify structural problems.

7Implement comprehensive error handling

Distinguish between different JWT error types for better debugging:

javascript
const jwt = require('jsonwebtoken');

function verifyTokenWithErrorHandling(token, secret) {
  try {
    const decoded = jwt.verify(token, secret);
    return { success: true, data: decoded };
  } catch (error) {
    // Handle specific JWT error types
    if (error.name === 'JsonWebTokenError') {
      if (error.message === 'invalid token') {
        return {
          success: false,
          error: 'INVALID_TOKEN',
          message: 'Token structure is malformed or corrupted',
          details: error.message,
        };
      } else if (error.message === 'jwt malformed') {
        return {
          success: false,
          error: 'MALFORMED_TOKEN',
          message: 'Token does not have three parts',
          details: error.message,
        };
      } else if (error.message.includes('invalid signature')) {
        return {
          success: false,
          error: 'INVALID_SIGNATURE',
          message: 'Token signature verification failed',
          details: error.message,
        };
      }
    } else if (error.name === 'TokenExpiredError') {
      return {
        success: false,
        error: 'TOKEN_EXPIRED',
        message: 'Token has expired',
        expiredAt: error.expiredAt,
      };
    }
    
    return {
      success: false,
      error: 'UNKNOWN_ERROR',
      message: error.message,
    };
  }
}

// Express middleware
function authMiddleware(req, res, next) {
  const token = req.headers.authorization?.replace('Bearer ', '');
  
  if (!token) {
    return res.status(401).json({ error: 'No token provided' });
  }
  
  const result = verifyTokenWithErrorHandling(token, process.env.JWT_SECRET);
  
  if (!result.success) {
    console.error('JWT verification failed:', result);
    return res.status(401).json(result);
  }
  
  req.user = result.data;
  next();
}

This provides detailed error context for debugging.

Advanced notes

Base64URL vs Base64 Encoding: JWTs use Base64URL encoding (RFC 4648 Section 5), not standard Base64. Base64URL replaces '+' with '-', '/' with '_', and omits padding '=' characters. If you manually construct or modify tokens, ensure you use the correct encoding.

Token Storage and Transmission: When storing tokens in databases or sending via HTTP headers, ensure no additional encoding/escaping is applied. Common issues include: storing tokens with surrounding quotes in databases, double-encoding tokens, or URL-encoding tokens when they should remain as-is.

Secret Key Consistency: The JWT_SECRET used in jwt.verify() must exactly match the secret used in jwt.sign(). Even minor differences (trailing spaces, quotes, different environment variables) will cause verification to fail. Use process.env directly without additional parsing.

Algorithm Mismatches: If tokens are generated with one algorithm (e.g., RS256 using public/private keys) but verified with another (e.g., HS256 expecting a shared secret), you'll get parsing errors. Always specify the algorithm explicitly in both sign() and verify() options.

Debugging Production Issues: In production, tokens may be corrupted by: CDN/proxy modifications, browser extensions, CORS preflight handling, or mobile app HTTP libraries. Log token lengths and first/last characters (not full tokens for security) to identify truncation or corruption patterns.

Security Considerations: Never log complete tokens in production as they grant authentication access. Instead, log only metadata (token length, expiration time, user ID from payload after successful verification). When debugging "invalid token" errors, use token structure validation without exposing sensitive data.

Frequently asked questions

What does "JsonWebTokenError" mean?
js jsonwebtoken library when it cannot successfully parse or decode a JWT (JSON Web Token) during the verification process. This is a structural parsing failure, meaning the library encountered a token that doesn't meet the basic format requirements of a valid JWT. signature.
How do I fix "JsonWebTokenError"?
This error occurs when the jsonwebtoken library fails to parse or decode a JWT token during verification. The token structure is malformed, corrupted, or contains invalid encoding that prevents successful parsing.
What causes "JsonWebTokenError"?
Token passed to jwt.verify() is null, undefined, or empty string Token does not have exactly three dot-separated components (header.payload.signature) Token contains "Bearer " or "JWT " prefix that was not stripped before verification
Is the "JsonWebTokenError" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading