WebDevWorker Guides & Tutorials
🔍
🔐 Security & Auth

How to Decode a JWT Token: Complete Tutorial (2026)

📅 Updated September 2026 ✓ 100% Client-Side Sandbox ⏱️ 10 min read 🏢 Zaviyan LLC

🔐 Live Developer Workstation

Paste any JWT and instantly see its decoded header and payload, check expiry, and inspect claims — 100% client-side, your tokens never leave the browser.

Launch JWT Decoder in Live Sandbox →

1. What Is a JWT and Why You Need to Decode It

A JSON Web Token (JWT) is a compact, URL‑safe means of representing claims between two parties. It consists of three Base64URL‑encoded parts: a header that describes the token type and signing algorithm, a payload that carries the claims, and a signature that guarantees integrity. Decoding a JWT lets developers inspect the claims, verify expiration, and confirm that the token was signed with the expected secret or public key. In modern APIs, single‑page applications, and micro‑services, JWTs replace session cookies, so understanding their structure is essential for debugging authentication flows, troubleshooting authorization errors, and ensuring security compliance.

Because JWTs travel over the wire in plain text, any misconfiguration—such as using a weak signing secret or forgetting to set an exp claim—can expose your application to replay attacks or token forgery. By decoding the token with a trusted client‑side tool like the WebDevWorker JWT Decoder, you keep the token inside the browser, guaranteeing that sensitive data never leaves the user’s device. This guide walks you through the anatomy, a quick workflow, code examples in five languages, and a security checklist to keep your implementation robust.

2. JWT Anatomy: The Header.Payload.Signature Formula

The JWT format follows the header.payload.signature pattern, where each segment is Base64URL‑encoded. Below is a real‑world example token (line‑breaks added for readability):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikpv
aG4gRG9lIiwiaWF0IjoxNjkxMjM0NTY3LCJleHAi
OjE2OTEyNzA1Njd9
.
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

Header (first part) – declares the token type (JWT) and the signing algorithm (HS256). Decoded JSON:

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload (second part) – contains the claims. Decoded JSON:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1691234567,
  "exp": 1691270567
}

Signature (third part) – HMAC‑SHA256 of base64url(header) + "." + base64url(payload) signed with the secret key. The signature ensures that any alteration to the header or payload invalidates the token.

Standard registered claim names are listed in the table below. Understanding each claim helps you decide which ones to validate in your application.

ClaimDescription
issIssuer – identifies the principal that issued the JWT.
subSubject – identifies the principal that is the subject of the JWT.
audAudience – intended recipients; verification ensures the token is for your service.
expExpiration Time – Unix timestamp after which the token MUST NOT be accepted.
nbfNot Before – Unix timestamp before which the token MUST NOT be accepted.
iatIssued At – Unix timestamp when the token was issued.
jtiJWT ID – unique identifier for the token, useful for replay detection.

Remember that the header and payload are merely Base64URL strings; you can decode them with any Base64 decoder. For time‑based claims like exp or iat, the timestamp converter is handy.

3. Step-by-Step: Decode Any JWT in 30 Seconds

  1. Open the tool – Navigate to the WebDevWorker JWT Decoder. The interface runs 100% client‑side, so your token never leaves the browser.
  2. Paste the token – Copy the entire JWT string (including the two dots) into the input box.
  3. Read the header – The decoder instantly shows the decoded JSON header. Verify the alg matches your expected algorithm (e.g., HS256 or RS256).
  4. Inspect the payload – Claims appear in a formatted view. Look for exp, nbf, and iat. Use the linked timestamp converter if you need human‑readable dates.
  5. Check expiration – If exp is present, compare it to the current time. The tool highlights expired tokens in red.
  6. Verify the signature – Enter the secret key (for HMAC) or the public key (for RSA/ECDSA) in the verification field. The decoder recalculates the signature using the HMAC utility and confirms a match.
  7. Review warnings – The UI flags common misconfigurations such as missing exp, use of alg=none, or weak key lengths.

Following these steps ensures you quickly validate both the integrity and the temporal validity of any JWT without writing a single line of code.

4. Decode and Verify JWTs in Code: 5 Languages

Below are ready‑to‑copy snippets that decode a JWT and verify its signature. Replace YOUR_TOKEN and YOUR_SECRET (or public key) with your actual values.

JavaScript (Node.js) – jsonwebtoken

const jwt = require('jsonwebtoken');
const token = 'YOUR_TOKEN';
const secret = 'YOUR_SECRET';

try {
  const decoded = jwt.verify(token, secret, { algorithms: ['HS256'] });
  console.log('Header:', decoded.header);
  console.log('Payload:', decoded);
} catch (err) {
  console.error('Invalid token:', err.message);
}

Python – PyJWT

import jwt
token = 'YOUR_TOKEN'
secret = 'YOUR_SECRET'

try:
    decoded = jwt.decode(token, secret, algorithms=['HS256'])
    print('Payload:', decoded)
except jwt.ExpiredSignatureError:
    print('Token has expired')
except jwt.InvalidTokenError as e:
    print('Invalid token:', e)

Go – golang-jwt

package main

import (
    "fmt"
    "github.com/golang-jwt/jwt/v5"
)

func main() {
    tokenString := "YOUR_TOKEN"
    secret := []byte("YOUR_SECRET")

    token, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
        if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, fmt.Errorf("unexpected signing method")
        }
        return secret, nil
    })
    if err != nil || !token.Valid {
        fmt.Println("Invalid token:", err)
        return
    }
    fmt.Printf("Claims: %+v\n", token.Claims)
}

Rust – jsonwebtoken crate

use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String,
    exp: usize,
    // add other fields as needed
}

fn main() {
    let token = "YOUR_TOKEN";
    let secret = "YOUR_SECRET";

    let validation = Validation::new(Algorithm::HS256);
    match decode::(token, &DecodingKey::from_secret(secret.as_ref()), &validation) {
        Ok(data) => println!("Claims: {:?}", data.claims),
        Err(err) => eprintln!("Invalid token: {}", err),
    }
}

cURL (verify signature with HMAC) & PHP

# cURL – using OpenSSL to verify HMAC (requires base64url conversion)
TOKEN="YOUR_TOKEN"
SECRET="YOUR_SECRET"
HEADER=$(echo "$TOKEN" | cut -d. -f1)
PAYLOAD=$(echo "$TOKEN" | cut -d. -f2)
SIGNATURE=$(echo "$TOKEN" | cut -d. -f3)
EXPECTED=$(echo -n "$HEADER.$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" -binary | base64 | tr '+/' '-_' | tr -d '=')
if [ "$EXPECTED" = "$SIGNATURE" ]; then echo "Signature valid"; else echo "Invalid signature"; fi

# PHP example
getMessage();
}
?>

These snippets cover the most common environments. For RSA/ECDSA signatures, swap the HMAC secret for a PEM‑encoded public key and adjust the algorithm name accordingly.

5. Security Checklist: 7 Attacks That Target JWTs

Attack VectorHow to Prevent
alg=none misuseReject tokens where alg is none unless explicitly allowed. Enforce algorithm whitelist on the server.
Weak secret / brute‑forceUse a secret of at least 256 bits for HMAC, rotate regularly, and store it in a secret manager.
Missing exp claimAlways include an expiration time and reject tokens without it.
kid injectionValidate the kid against a known list of keys; never fetch keys from untrusted URLs.
XSS token theftStore JWTs in httpOnly cookies or secure storage; never expose them to JavaScript unless necessary.
Replay attacksImplement token revocation lists or short‑lived access tokens combined with refresh tokens.
Algorithm downgradeHard‑code the expected algorithm on verification; never trust the token‑provided alg value alone.

By following this checklist you mitigate the most common vulnerabilities. For deeper analysis, refer to the full guide How to Decode a JWT Token: Complete Tutorial (2026).

6. Frequently Asked Questions (FAQs)

Can I decode a JWT without the secret key?

Yes. The header and payload are only Base64URL‑encoded, so anyone can decode them without a secret. However, verifying the signature requires the secret (for HMAC) or the public key (for RSA/ECDSA). Use the WebDevWorker JWT Decoder to safely view claims client‑side.

How do I check if a JWT token is expired?

Inspect the exp claim, which is a Unix timestamp. Convert it with the timestamp converter or compare it to Date.now()/1000 in code. The WebDevWorker decoder highlights expired tokens automatically.

Is it safe to paste a JWT into an online decoder?

Only if the tool runs entirely in the browser. WebDevWorker’s decoder is 100% client‑side, meaning the token never leaves your device, which makes it safe for sensitive tokens.

What is the difference between iat and nbf?

iat (Issued At) marks when the token was created. nbf (Not Before) defines the earliest time the token is considered valid. Both are Unix timestamps; use them together to enforce strict time windows.

How can I verify a JWT signed with RSA?

Load the RSA public key (PEM format) into your verification library and specify the algorithm (e.g., RS256). The signature is verified using the public key; the secret is never needed.

Why should I avoid using alg=none?

alg=none disables signature verification, allowing anyone to forge a token. Most libraries reject it by default; always enforce a strong algorithm like HS256 or RS256.

Ready to accelerate your workflow?

Launch the interactive zero-telemetry utility in your browser right now.

Launch JWT Decoder Now →