How to decode JWT Token?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
A JWT is just a compact string with three dot-separated parts: header, payload, and signature. Decoding it is useful for inspection and debugging, but decoding alone does not prove the token is trustworthy.
That distinction is the most important thing to understand. Anyone who has the token can base64url-decode the first two sections. Only signature verification tells you whether the token was issued by a trusted signer and has not been modified.
What It Means to Decode a JWT
A JWT usually looks like this:
The header and payload are base64url-encoded JSON. The signature is a cryptographic check value created from the first two parts plus a secret or private key.
So there are really two separate operations:
- decode the token to read claims
- verify the token before trusting those claims
If you only need to inspect the contents during development, decoding is enough. If the token influences authentication or authorization, verification is mandatory.
Decoding Without Verification
Here is a Python example using PyJWT to read the payload without verifying the signature:
This is useful for debugging, but the resulting claims must be treated as untrusted input.
You can also manually decode the payload to understand what is happening:
That demonstrates the structure, but it does not validate the signature.
Verifying the JWT Correctly
In real applications, use a library that verifies the signature and claims in one step. With a shared-secret algorithm such as HS256, the server verifies using the same secret that was used to sign the token.
If the signature is wrong, the algorithm does not match, or the token is expired, the library raises an exception.
In Node.js with jsonwebtoken, the flow is similar:
Use verify, not just decode, when security decisions depend on the result.
Reading Common Claims
Once the token is verified, you can inspect standard claims such as:
- '
subfor subject or user identifier' - '
expfor expiration time' - '
iatfor issued-at time' - '
issfor issuer' - '
audfor audience'
Libraries can validate some of these automatically if you provide the expected values. For example, checking aud and iss helps prevent accepting tokens meant for a different service.
That is much safer than verifying only the signature and then accepting every claim at face value.
Why Base64 Decoding Is Not Enough
Because the payload is only encoded, not encrypted, anyone with the token can read its claims. A malicious user can also edit the header and payload locally and produce a new string. Without signature verification, your application cannot distinguish a valid token from a forged one.
This is the core security rule: decode for visibility, verify for trust.
Common Pitfalls
The biggest mistake is calling a decode helper and then treating the payload as authenticated identity data. That creates an authorization bug immediately.
Another issue is accepting whatever algorithm the token header says. Good libraries let you specify the allowed algorithms explicitly. Do that, rather than trusting the token to declare its own rules.
Expiration handling also trips people up. A successfully decoded token may still be expired. Use verification methods that enforce exp, and handle clock skew only when you have a clear reason.
Finally, do not assume JWT contents are secret. Unless a separate encryption standard is used, JWT payloads are readable by anyone who has the token. Avoid putting sensitive data in them.
Summary
- A JWT has header, payload, and signature sections.
- Decoding reads the claims, but it does not prove the token is valid.
- Use library verification methods such as
jwt.decodewith a key in Python orjwt.verifyin Node.js. - Validate claims such as
exp,iss, andaudwhen they matter. - Treat decoded but unverified payload data as untrusted input.

