How to Decode JWT Tokens

A complete guide to understanding, decoding, and inspecting JSON Web Tokens with practical code examples in JavaScript and Python.

What Is a JWT Token?

A JSON Web Token (JWT) is a compact, URL-safe format for transmitting claims between two parties. JWTs are widely used for authentication and authorization in web applications, APIs, and microservices architectures. When a user logs in, the server issues a JWT that the client sends with subsequent requests to prove identity.

JWTs have become the industry standard for stateless authentication because they eliminate the need for server-side session storage. Instead of looking up session data in a database on every request, the server simply verifies the token's signature and reads the claims directly from the payload.

The Three Parts of a JWT

Every JWT consists of three Base64URL-encoded parts separated by dots:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiaWF0IjoxNjE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Header — The first segment contains metadata about the token, including the signing algorithm (alg) and token type (typ). Common algorithms include HS256 (HMAC with SHA-256), RS256 (RSA with SHA-256), and ES256 (ECDSA with P-256).

Payload — The second segment carries the claims. These are key-value pairs that describe the user or session. Standard claims include sub (subject), iss (issuer), exp (expiration), iat (issued at), and aud (audience). You can also add custom claims like role or permissions.

Signature — The third segment is a cryptographic hash that protects the header and payload from tampering. The server uses a secret key (HMAC) or private key (RSA/ECDSA) to generate the signature, and verifies it before trusting the token's contents.

Decoding a JWT in JavaScript

Since the header and payload are simply Base64URL-encoded JSON, decoding a JWT does not require the signing key. You can decode it in a few lines of JavaScript using the built-in atob function:

function decodeJWT(token) {
  const parts = token.split('.');
  if (parts.length !== 3) {
    throw new Error('Invalid JWT: expected 3 parts');
  }

  // Base64URL to Base64 conversion
  const base64Decode = (str) => {
    const base64 = str.replace(/-/g, '+').replace(/_/g, '/');
    return JSON.parse(atob(base64));
  };

  return {
    header: base64Decode(parts[0]),
    payload: base64Decode(parts[1]),
  };
}

// Usage
const token = 'eyJhbGciOiJIUzI1NiIs...';
const { header, payload } = decodeJWT(token);
console.log('Algorithm:', header.alg);
console.log('Subject:', payload.sub);
console.log('Expires:', new Date(payload.exp * 1000));

In Node.js, you can use Buffer.from(str, 'base64') instead of atob. For production applications, consider using a library like jose or jsonwebtoken that handles edge cases, validates claims, and verifies signatures.

Decoding a JWT in Python

Python's standard library includes everything you need to decode a JWT. The base64 module handles the URL-safe Base64 decoding, and json parses the resulting strings:

import base64
import json

def decode_jwt(token):
    parts = token.split('.')
    if len(parts) != 3:
        raise ValueError('Invalid JWT: expected 3 parts')

    def base64url_decode(s):
        # Add padding if needed
        s += '=' * (4 - len(s) % 4)
        decoded = base64.urlsafe_b64decode(s)
        return json.loads(decoded)

    return {
        'header': base64url_decode(parts[0]),
        'payload': base64url_decode(parts[1]),
    }

# Usage
token = 'eyJhbGciOiJIUzI1NiIs...'
result = decode_jwt(token)
print('Algorithm:', result['header']['alg'])
print('Subject:', result['payload']['sub'])

For production use, the PyJWT library provides signature verification, claim validation, and support for RSA and ECDSA keys. Install it with pip install PyJWT and use jwt.decode(token, key, algorithms=["HS256"]) to both decode and verify in one step.

Common JWT Claims Explained

The JWT specification (RFC 7519) defines a set of registered claims that you will encounter frequently:

  • iss (Issuer) — Identifies who created and signed the token, such as your authentication server's URL.
  • sub (Subject) — Identifies the principal the token is about, typically a user ID.
  • aud (Audience) — Identifies the recipients the token is intended for, preventing token misuse across services.
  • exp (Expiration Time) — A Unix timestamp after which the token must be rejected. Always check this claim server-side.
  • iat (Issued At) — A Unix timestamp indicating when the token was created.
  • nbf (Not Before) — A Unix timestamp before which the token must not be accepted.
  • jti (JWT ID) — A unique identifier for the token, useful for preventing replay attacks.

Applications frequently add custom claims such as role, permissions, email, or org_id. Keep payloads small since the token is sent with every request.

Security Best Practices

Decoding a JWT is straightforward, but handling tokens securely requires care. Follow these guidelines to avoid common pitfalls:

  • Always verify the signature server-side before trusting any claims. Decoding without verification tells you what the token says, but not whether it is authentic.
  • Check the exp claim on every request. Expired tokens should be rejected immediately.
  • Validate the iss and aud claims to ensure the token was issued by your authentication server and intended for your application.
  • Never store sensitive data in the payload. The payload is encoded, not encrypted. Anyone with the token can read it.
  • Use short expiration times and implement token refresh flows to limit the window of exposure if a token is compromised.
  • Store tokens securely on the client side. Prefer httpOnly cookies over localStorage to reduce the risk of XSS attacks.

Try It Yourself

Want to decode a JWT token right now without writing any code? Use our free, browser-based JWT Decoder tool. It runs entirely in your browser, so your tokens are never sent to a server.

Open the JWT Decoder Tool →

Frequently Asked Questions

Can you decode a JWT without the secret key?

Yes. The header and payload of a JWT are only Base64URL-encoded, not encrypted. Anyone can decode and read them without the secret key. The secret key is only needed to verify the signature, which confirms the token has not been tampered with. This is why you should never store sensitive data like passwords in a JWT payload.

Is it safe to decode JWT tokens in the browser?

It is safe as long as the tool processes tokens entirely client-side. Browser-based decoders like the one on Janeer never send your token to a server, so your data stays private. Avoid tools that transmit tokens to a backend for processing, as that could expose sensitive claims such as user IDs, email addresses, and roles.

What is the difference between decoding and verifying a JWT?

Decoding a JWT means reading the header and payload by Base64URL-decoding the first two parts of the token. Verifying a JWT means checking the cryptographic signature to confirm the token was issued by a trusted party and has not been modified. Decoding can be done by anyone; verification requires the signing key and should always happen server-side before trusting the token's claims.