JWT Tokens Explained: How Authentication Works in Modern Web Apps — and How to Decode Them
Developer Tools

JWT Tokens Explained: How Authentication Works in Modern Web Apps — and How to Decode Them

IP Pulse Pro TeamMay 15, 202616 min read
Share:
TL;DR: A JWT (JSON Web Token) is a compact, URL-safe token that carries claims between parties. It has three parts — header, payload, and signature — each Base64URL-encoded and separated by dots. Decode any JWT instantly with our JWT Decoder Tool.

What Is a JWT?

A JSON Web Token, or JWT (pronounced "jot"), is an open standard (RFC 7519) for securely transmitting information between parties as a JSON object. Think of it as a digital passport: it contains claims (statements about an entity) that can be verified and trusted because they are digitally signed.

JWTs have become the dominant mechanism for authentication in modern web applications. When you log in to a web app, the server typically issues a JWT, and your browser includes it with every subsequent request. The server verifies the token's signature and extracts your identity from it — no session lookup required.

The key insight is that a JWT is self-contained. Unlike a session ID that is just a random string pointing to server-side data, a JWT carries its own data. This makes JWTs ideal for distributed systems where the service processing a request may not have direct access to the authentication database.

The JWT Flow: From Login to Verified Request User Login Auth Server Signs and Issues JWT Client Stores JWT in Memory API Server Verifies Signature JWT = Header.Payload.Signature eyJhbGciOiJIUzI1NiJ9 eyJzdWIiOiJ1c2VyMTIzIn0 SflKxwRJSMeKKF2QT4 Header (Algorithm) Payload (Claims) Signature (Proof)

The Three Parts of a JWT

A JWT looks like a long string with two dots separating three sections:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

The Header

The header is a JSON object that specifies the token type and signing algorithm:

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

This is Base64URL-encoded to produce the first segment. Common algorithms include HS256 (HMAC with SHA-256), RS256 (RSA Signature with SHA-256), and ES256 (ECDSA with SHA-256).

The Payload

The payload contains the claims — the actual data being transmitted. There are three types of claims:

Claim TypeExamplesDescription
Registerediss, sub, aud, exp, iat, jtiPredefined by the JWT spec, recommended for interoperability
Publicname, email, roleCustom claims defined by you, should be registered in the IANA JWT registry to avoid collisions
Privateorg_id, permission_levelApp-specific claims, use namespaced keys to avoid collisions (e.g., "https://myapp.com/role")
Warning: The payload is only encoded, not encrypted. Never put sensitive data like passwords or social security numbers in a JWT payload. Anyone with the token can decode it.

The Signature

The signature is what makes a JWT trustworthy. For HS256, it is created by taking the Base64URL-encoded header, a dot, the Base64URL-encoded payload, and signing it with a secret key using HMAC SHA-256:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

For RS256, the server signs with its private key and any party can verify using the public key. This is why RS256 is preferred for microservice architectures — services only need the public key to verify tokens.

JWT vs Session-Based Auth

Understanding when to use JWT versus traditional sessions is crucial. Here is an honest comparison:

AspectJWTSessions
Server stateStatelessStateful (server stores session data)
ScalabilityEasy — any server can verifyRequires shared session store
RevocationHard — token lives until expiryEasy — delete the session
Token sizeLarge (1-4KB+)Small (cookie with session ID)
Mobile friendlyYes — no cookies neededCookie management is awkward
CSRFImmune (if in Authorization header)Vulnerable — needs CSRF tokens
Key Takeaway: Use JWT when you need stateless authentication across services (APIs, microservices, mobile apps). Use sessions when you need immediate revocation, have a simple monolithic app, or are working with server-rendered pages.

How JWT Authentication Works

A typical JWT authentication flow looks like this:

  1. User logs in with credentials (email/password) sent over HTTPS.
  2. Server verifies credentials against the database.
  3. Server creates a JWT containing the user's identity (sub claim), roles, and an expiration time, then signs it with its secret or private key.
  4. Server sends the JWT back to the client in the response body (never in a URL).
  5. Client stores the token — in memory for access tokens, in an HttpOnly cookie for refresh tokens.
  6. Client includes the token in the Authorization: Bearer <token> header of every API request.
  7. Server verifies the signature on each request, checks expiration, and extracts the claims to identify the user.
Decode Tokens Instantly
Paste any JWT into the JWT Decoder to see its header, payload, and signature details — no installation needed.
Encode Data Safely
Need to encode or decode Base64? Use the Base64 Tool to understand the encoding layer of JWTs.

Critical JWT Vulnerabilities

JWTs are powerful, but they come with real security pitfalls. Here are the most dangerous ones:

1. Algorithm Confusion Attack

If your server accepts multiple algorithms, an attacker can change the alg header from RS256 to HS256. Now the server will try to verify the token using HMAC with the RSA public key as the secret — and if the attacker knows the public key (which is public!), they can forge valid tokens.

Critical Fix: Always explicitly specify which algorithm(s) your server accepts. Never trust the alg field from the token header alone.

2. "None" Algorithm

Some JWT libraries accept "alg": "none", which means the token has no signature. An attacker can set this header and modify the payload freely. Modern libraries reject this, but older versions may not.

3. Weak Secret Keys

If you use HS256 with a weak secret like "secret" or "password123", an attacker can brute-force it and sign arbitrary tokens. Your HMAC secret should be at least 256 bits (32 bytes) of cryptographically random data.

4. Token Theft via XSS

If you store JWTs in localStorage or accessible cookies, any XSS vulnerability on your site gives the attacker full access to tokens. This is why storing access tokens in memory (not localStorage) and using HttpOnly cookies for refresh tokens is the recommended pattern.

5. Missing Expiration

A JWT without an exp claim never expires. If it is stolen, the attacker has access forever. Always set short expiration times on access tokens.

JWT Vulnerability Severity Matrix Algorithm Confusion CRITICAL "None" Algorithm CRITICAL Weak Secret Key HIGH XSS Token Theft HIGH Missing Expiration MEDIUM Payload in URL MEDIUM No Audience Check LOW-MEDIUM Always validate alg, exp, aud, iss, and nbf claims on the server

How to Decode a JWT

Decoding a JWT is straightforward because the header and payload are just Base64URL-encoded JSON. You do not need the secret key to read them — you only need it to verify the signature.

Here is how to decode a JWT manually:

// Split the token into its three parts
const [headerB64, payloadB64, signatureB64] = token.split('.');

// Decode each part
const header = JSON.parse(atob(headerB64.replace(/-/g, '+').replace(/_/g, '/')));
const payload = JSON.parse(atob(payloadB64.replace(/-/g, '+').replace(/_/g, '/')));

console.log('Algorithm:', header.alg);
console.log('Subject:', payload.sub);
console.log('Expires:', new Date(payload.exp * 1000));

Or, skip the manual work and use our JWT Decoder Tool — paste any token and instantly see the decoded header, payload, and signature status.

HS256 RS256 ES256 Base64URL Bearer Token OAuth 2.0

JWT Best Practices

Use Short-Lived Access Tokens

Set exp to 5-15 minutes. If a token is compromised, the damage window is minimal. Pair with a longer-lived refresh token stored in an HttpOnly cookie.

Prefer RS256 Over HS256

Asymmetric signing means only the auth server knows the private key, while any service can verify with the public key. This eliminates the need to share secrets across services.

Always Validate All Claims

Check exp (not expired), iss (correct issuer), aud (correct audience), and nbf (not before). Skipping any of these is a security vulnerability.

Store Tokens Safely

Access tokens in JavaScript memory (lost on page refresh but safe from XSS). Refresh tokens in HttpOnly, Secure, SameSite cookies. Never in localStorage for sensitive apps.

When Not to Use JWT

JWT is not a silver bullet. There are situations where sessions are genuinely better:

  • When you need instant revocation: Logging out should immediately invalidate the token. With JWT, you need a blacklist (which reintroduces server state).
  • When your token would be huge: If you need to carry dozens of permissions or large datasets, a JWT can easily exceed several kilobytes, adding overhead to every request.
  • When you have a simple monolith: If you are building a single-server app, sessions are simpler, more secure, and have none of JWT's complexity.
  • When real-time data is needed: If user permissions change frequently, a JWT cannot reflect those changes until it is reissued. Sessions always reflect the current state.
Decode any JWT in seconds. Paste your token and instantly see header, payload, and signature details with our free JWT Decoder.
Open JWT Decoder

Try JWT Decoder Tool

Instantly decode and inspect any JWT token. See header, payload, and signature breakdown in real-time.

Use Tool

Frequently Asked Questions

Cookie Preferences

We use essential cookies for authentication and security. On blog pages, Google AdSense may set advertising cookies for free-tier visitors to show relevant ads. You can manage your preferences below.