Skip to content

/commands/jwt/decode-jwt-command-line

Decode a JWT from the command line (header and payload)

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated 2026-10-20
tool
JWT
versions
RFC 7519
os
any

A JSON Web Token is header.payload.signature, each part base64url-encoded. To read the header and claims, split on the dots and base64url-decode the first two parts. Decoding needs no key, and it proves nothing: anyone can read a JWT, and only verifying the signature tells you it is genuine.

Decode with Node.js

The token below is an example built for this page (signature part shortened):

bash
JWT='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkV4YW1wbGUgVXNlciIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAzNjAwfQ.c2lnbmF0dXJl'
node -e '
const [h, p] = process.argv[1].split(".");
const dec = (s) => JSON.parse(Buffer.from(s, "base64url").toString());
console.log("header: ", dec(h));
const payload = dec(p);
console.log("payload:", payload);
console.log("expires:", new Date(payload.exp * 1000).toISOString());' "$JWT"

Output

header:  { alg: 'HS256', typ: 'JWT' }
payload: {
  sub: '1234567890',
  name: 'Example User',
  iat: 1760000000,
  exp: 1760003600
}
expires: 2025-10-09T09:53:20.000Z

Decode with base64

base64url uses - and _ and drops padding, so translate and pad before base64 -d:

bash
JWT='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkV4YW1wbGUgVXNlciIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAzNjAwfQ.c2lnbmF0dXJl'
part=$(echo "$JWT" | cut -d. -f2 | tr '_-' '/+')
while [ $(( ${#part} % 4 )) -ne 0 ]; do part="$part="; done
echo "$part" | base64 -d; echo

Output

{"sub":"1234567890","name":"Example User","iat":1760000000,"exp":1760003600}

Claims you will see

ClaimMeaning
ississuer
subsubject (usually the user id)
audaudience the token is meant for
expexpiry time, seconds since the Unix epoch
nbfnot valid before
iatissued at
jtiunique token id

Sources