JsonWebTokenError: secret or public key must be provided: what it means and how to fix it

TL;DR: Validate locally, fix the first real error, validate again (no upload).

Fix JsonWebTokenError: secret or public key must be provided by decoding safely and locally (no upload).

What the error means

JsonWebTokenError: secret or public key must be provided means a decoder rejected the input as invalid encoding. The fastest path is to identify what format you have, normalize it, then decode again.

Most common real-world causes

  • Your verification step did not receive a signing key (secret/public key).
  • You called verify/decode with an empty/undefined token.
  • JWT problems are often: not 3 segments, wrong key/algorithm, or option mismatch (aud/iss/sub).
  • The input is not actually encoded in the expected format (Base64 vs Base64URL vs plain text).
  • You copied only part of the string (truncated token/payload).
  • Whitespace/newlines were introduced during copy/paste.
  • Wrong character set: URL-safe Base64 uses '-' and '_' instead of '+' and '/'.
  • You decoded using the wrong function (decodeURIComponent on non-URL-encoded data, atob on non-Base64).

Fast debugging steps

  • If you see a JWT library error, decode the token parts first to confirm structure and claims.
  • Confirm what you are decoding (URL encoding, Base64, Base64URL, JWT).
  • Trim whitespace and remove line breaks before decoding.
  • If it's a JWT, ensure it has 3 dot-separated parts (header.payload.signature).
  • If it's Base64URL, convert '-' -> '+' and '_' -> '/' and add padding if needed.

Code example (node)

// Node (jsonwebtoken) troubleshooting
const jwt = require('jsonwebtoken');

try {
  // 1) Quick structure check
  if (token.split('.').length !== 3) throw new Error('JWT must have 3 segments');

  // 2) Inspect claims WITHOUT verifying (debug only)
  const decoded = jwt.decode(token, { complete: true });
  console.log(decoded);

  // 3) If you need verification: provide correct key + options
  // const payload = jwt.verify(token, publicKeyOrSecret, { algorithms: ['HS256'] });
  // console.log(payload);
} catch (e) {
  console.error(e.name || 'Error', e.message || String(e));
}

Fix without uploading data

Encoded strings often contain secrets (tokens, IDs). Decode locally and share only redacted snippets.

FAQ

Is Base64 the same as Base64URL? No. Base64URL uses '-' and '_' and often omits padding. Normalize before decoding.

Does decoding a JWT verify it? No. Decoding shows claims; verification requires the signing key.

Privacy & Security
All processing happens locally in your browser. Files are never uploaded.