JSON Web Tokens (JWTs) are the standard for authentication and authorization in modern web applications. Whether you are building a REST API, implementing OAuth, or debugging a login flow, understanding how to decode and inspect JWTs is an essential skill for any developer.
A JWT (pronounced "jot") is a compact, URL-safe token format defined by RFC 7519. It allows you to securely transmit information between parties as a JSON object. The token is digitally signed, so the receiver can verify its authenticity.
A JWT looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkRldlRvb2xLaXQiLCJpYXQiOjE3MTY5MjAwMDB9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Every JWT consists of three parts separated by dots (.):
The header typically contains the signing algorithm and token type. It is Base64URL-encoded:
{
"alg": "HS256",
"typ": "JWT"
}
Common algorithms include HS256 (HMAC-SHA256), RS256 (RSA-SHA256), and ES256 (ECDSA-SHA256).
The payload carries the actual data as "claims" — statements about the user and metadata:
{
"sub": "1234567890",
"name": "DevToolKit",
"email": "[email protected]",
"role": "admin",
"iat": 1716920000,
"exp": 1717006400
}
The signature verifies the token has not been tampered with. It is computed using the algorithm specified in the header:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
| Claim | Name | Description |
|---|---|---|
iss | Issuer | Who issued the token (e.g., your auth server) |
sub | Subject | The user or entity the token is about |
aud | Audience | Intended recipient of the token |
exp | Expiration | Unix timestamp when the token expires |
nbf | Not Before | Token is not valid before this time |
iat | Issued At | When the token was created |
jti | JWT ID | Unique identifier to prevent replay attacks |
Use the Unix Timestamp Converter to convert exp and iat values to human-readable dates.
exp claim to see if the token has expired.role, scope, or permissions.The most common issue. Decode the token and check the exp claim against the current Unix timestamp. If exp is in the past, the token has expired and needs to be refreshed.
// exp: 1716920000 = May 28, 2024 16:53:20 UTC
// Current time is past this? Token expired.
This happens when the token was signed with a different secret or key than what the server expects. Common causes:
If the aud claim does not match the expected API or service identifier, the token will be rejected. This is common in multi-service architectures.
Never trust the alg header blindly. A known attack involves changing alg from RS256 to HS256 and signing with the public key as the HMAC secret. Always validate the algorithm server-side.
iss, aud, exp, and nbf on every request.# Decode JWT in the terminal
echo "eyJhbGciOiJIUzI1NiJ9" | base64 -d
# Output: {"alg":"HS256"}
# Using jq for pretty output
echo "eyJhbGciOiJIUzI1NiJ9" | base64 -d | jq .
# Python
import jwt
decoded = jwt.decode(token, secret, algorithms=["HS256"])
# Node.js (jsonwebtoken)
const jwt = require('jsonwebtoken');
const decoded = jwt.verify(token, secret);
Yes. The header and payload are only Base64URL-encoded, not encrypted. You can always read them. The secret is only needed to verify the signature.
Yes. DevToolKit's JWT decoder runs entirely client-side. Your tokens are never sent to any server.
JWS (JSON Web Signature) is what most people mean by "JWT" — the payload is signed but readable. JWE (JSON Web Encryption) encrypts the payload, so it cannot be read without the decryption key.
Try JWT Decoder Now →DevToolKit — 42+ Free Online Developer Tools