How to Debug JWTs Without Pasting Them Into jwt.io
jwt.io is the first place most developers go to decode a JWT. It's convenient — but every token you paste there contains your authentication state. Here's the problem and the safer alternatives.
What a JWT actually contains
A JWT has three base64url-encoded parts separated by dots: header.payload.signature. The payload typically contains your user ID, roles, expiry time, and any claims your application adds. Pasting a live JWT into a third-party service means that service can see all of this.
// Decode in your browser console (no tools needed)
const [header, payload] = "eyJhbGci...".split(".")
console.log(JSON.parse(atob(header))) // { alg: "HS256", typ: "JWT" }
console.log(JSON.parse(atob(payload))) // { sub: "user_123", exp: 1711928400 }The real risk with jwt.io
jwt.io decodes tokens client-side in your browser — the token is not sent to their server. For the decoding use case, this is relatively safe. The risk is habit: developers who routinely paste tokens into external tools eventually paste a production token with a long expiry, or paste one in a screen recording, or leave it in a chat log.
The lower-risk habit: decode in your browser console or use a local tool.
Decode without any tool (curl + jq)
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." # Decode header echo $TOKEN | cut -d. -f1 | base64 --decode 2>/dev/null | jq . # Decode payload echo $TOKEN | cut -d. -f2 | base64 --decode 2>/dev/null | jq .
Common JWT errors and what they mean
- TokenExpiredError — the
expclaim is in the past. Refresh the token. - JsonWebTokenError: invalid signature — the token was signed with a different secret, or the payload was tampered with.
- JsonWebTokenError: jwt malformed — the token string is missing a segment or has invalid base64 characters.
- NotBeforeError — the
nbf(not before) claim is in the future. The token is valid but can't be used yet. - Algorithm mismatch — the token header says
RS256but your verifier is configured forHS256. Always verifyalgexplicitly.
Verify a JWT in Node.js
import jwt from "jsonwebtoken"
try {
const payload = jwt.verify(token, process.env.JWT_SECRET!, {
algorithms: ["HS256"], // Always specify — don't allow "none"
})
console.log(payload)
} catch (err) {
if (err instanceof jwt.TokenExpiredError) // handle expiry
if (err instanceof jwt.JsonWebTokenError) // handle invalid
}Need to decode or verify a JWT without pasting it into an external service? Aarunya JWT Debugger runs entirely in your browser — the token never leaves your tab. Supports HS256, RS256, ES256, and 9 more algorithms.
Enjoyed this? Get notified when Pro launches.
