// blog/developer/
Back to Blog
Developer · May 20, 2026 · 9 min read · Updated May 22, 2026

JWT Tokens: How to Decode, Verify, and Debug Tokens

JWT Tokens: How to Decode, Verify, and Debug Tokens

If you have built any web application in the last decade, you have probably encountered JWTs. They are the long, ugly strings that show up in authorization headers, cookie values, and URL parameters. They look like random noise, but they are actually structured data that your application uses to verify who a user is and what they are allowed to do.

A JSON Web Token is a compact, URL-safe way to represent claims between two parties. In plain terms: it is a digitally signed piece of JSON that proves someone's identity without requiring a database lookup on every request. The server creates the token when the user logs in, the client stores it, and the client sends it back with every subsequent request. The server verifies the signature and trusts the claims inside.

The beauty of JWTs is statelessness. The server does not need to store session data. The downside is that once issued, a JWT is valid until it expires, and revoking it before expiration is not straightforward. Understand this tradeoff before you commit to JWT-based authentication.

* * *

The Three Parts of a JWT

Every JWT consists of three Base64-encoded segments separated by dots:

` eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U `

Header (first segment): Contains the token type and signing algorithm. Decoded, it looks like: `json { "alg": "HS256", "typ": "JWT" } `

Payload (second segment): Contains the claims. These are statements about the user and any additional data: `json { "sub": "1234567890", "name": "Jane Smith", "role": "admin", "iat": 1716000000, "exp": 1716003600 } `

Signature (third segment): Created by taking the encoded header and payload, combining them with a dot, and signing the result with the algorithm specified in the header using a secret key.

You can decode the header and payload with any Base64 Encoder/Decoder because they are just Base64-encoded JSON. The signature, however, can only be verified if you have the secret key (for HMAC algorithms) or the public key (for RSA/ECDSA algorithms).

Use the JSON Formatter to pretty-print decoded JWT payloads for easier reading during debugging.

Code editor showing authentication token logic
Code editor showing authentication token logic
* * *

How JWT Authentication Works in Practice

The typical flow in a web application goes like this:

  1. Login: The user sends credentials (email + password) to the server. The server verifies them against the database.
  1. Token creation: If credentials are valid, the server creates a JWT containing the user's ID, role, and an expiration time. It signs the token with a secret key and sends it back to the client.
  1. Storage: The client stores the token. Common options are localStorage, sessionStorage, or an httpOnly cookie. Each has different security implications (more on this later).
  1. Authenticated requests: On every subsequent request, the client includes the JWT in the Authorization header: Authorization: Bearer eyJhbGci...
  1. Verification: The server receives the request, extracts the JWT, verifies the signature, checks that the token has not expired, and reads the claims. If everything checks out, the request proceeds.
  1. Expiration: When the token expires, the client needs to re-authenticate or use a refresh token to get a new access token.

This flow means the server never needs to look up session data in a database or cache. All the information it needs is in the token itself, and the signature guarantees it has not been tampered with.

Key takeaway

The typical flow in a web application goes like this: 1.

* * *

Common JWT Security Mistakes

JWTs are often misused in ways that create serious security vulnerabilities:

Storing tokens in localStorage. Any JavaScript running on the page can read localStorage, which means a single XSS vulnerability gives an attacker full access to the token. Use httpOnly cookies instead, which are not accessible to JavaScript.

Not validating the algorithm. Some JWT libraries allow the alg field in the header to override the expected algorithm. An attacker could change the algorithm to none (no signature required) and forge tokens. Always verify that the algorithm matches what your server expects.

Setting expiration times too far in the future. A token with a 30-day expiration is a 30-day window for an attacker who steals it. Use short-lived access tokens (5-15 minutes) paired with longer-lived refresh tokens stored securely.

Putting sensitive data in the payload. The payload is Base64-encoded, not encrypted. Anyone with the token can decode and read it. Never include passwords, credit card numbers, or other secrets in a JWT payload.

Not using HTTPS. JWTs sent over unencrypted HTTP can be intercepted by anyone on the network. Always use HTTPS in production.

Generating weak signing keys. For HMAC algorithms, your secret key needs to be cryptographically random and at least as long as the hash output (256 bits for HS256). Use the Hash Generator to understand hash lengths and experiment with different algorithms.

* * *

Debugging JWT Issues

When JWT authentication breaks, the error messages are often unhelpful. "Invalid token" could mean a dozen different things. Here is a systematic debugging approach:

Decode the token first. Paste it into a JWT decoder (or use a Base64 decoder) to read the header and payload. Check: - Is the exp claim in the past? The token is expired. - Is the iss (issuer) claim correct? It might be from a different environment (dev vs production). - Is the aud (audience) claim matching what your server expects?

Check the signature algorithm. If the header says RS256 but your server is configured for HS256, verification will fail silently with a generic error.

Inspect the full token string. Copy-paste errors can truncate tokens. A JWT must have exactly two dots. If it has fewer, part of the token is missing. Extra whitespace or newline characters (common when copying from logs) will also break parsing.

Compare timestamps. JWT timestamps (iat, exp, nbf) are Unix timestamps in seconds. Convert them to readable dates to check whether the token's time window makes sense. Is the nbf (not before) time in the future? The token is not valid yet.

Test with a fresh token. If a token from 10 minutes ago works but one from an hour ago does not, the issue is expiration. If neither works, the issue is likely signature verification or a server configuration problem.

Check clock skew. If the token-issuing server and the token-verifying server have slightly different clocks, tokens near their expiration boundary might work on one and fail on the other. Most JWT libraries support a small tolerance (30-60 seconds of clock skew).

Lock icon on a digital interface representing security
Lock icon on a digital interface representing security
* * *

JWTs vs Session Cookies

The debate between JWTs and traditional session cookies is one of the most discussed topics in web authentication. Here is a practical comparison:

Session cookies store a session ID in a cookie. The actual session data lives on the server (in memory, a database, or Redis). Every request requires a server-side lookup. This is simple, battle-tested, and easy to revoke (just delete the session from the store).

JWTs store the session data in the token itself. No server-side storage needed. This is great for scaling across multiple servers because any server can verify the token independently. But revocation is hard. To invalidate a JWT before expiration, you need a blacklist, which re-introduces server-side state and partially defeats the purpose.

For most web applications, session cookies are simpler and more secure. Use them unless you have a specific reason not to (like a microservices architecture where multiple services need to verify the same token independently, or a mobile app where cookies are inconvenient).

JWTs shine in specific scenarios: API authentication for third-party services, single sign-on (SSO) across multiple applications, and stateless microservices that need to scale horizontally without shared session stores.

* * *

Refresh Token Patterns

Short-lived access tokens improve security, but asking users to log in every 15 minutes is terrible UX. Refresh tokens solve this.

The pattern works like this:

  1. On login, the server issues two tokens: a short-lived access token (5-15 minutes) and a long-lived refresh token (days or weeks).
  1. The client uses the access token for API requests until it expires.
  1. When the access token expires, the client sends the refresh token to a dedicated endpoint to get a new access token.
  1. The server verifies the refresh token, checks that it has not been revoked, and issues a new access token.

Refresh tokens should be stored more securely than access tokens. An httpOnly, secure, sameSite cookie is the best option for web applications. They should also be rotated: every time a refresh token is used, the old one is invalidated and a new one is issued.

If an attacker steals a refresh token and tries to use it after the legitimate user has already used it, the server detects the reuse (the old token is already invalidated), revokes the entire token family, and forces a re-login. This is called refresh token rotation with reuse detection.

Key takeaway

Short-lived access tokens improve security, but asking users to log in every 15 minutes is terrible UX.

* * *

FAQ

Can a JWT be decrypted?

Standard JWTs (JWS) are signed but not encrypted. The payload is Base64-encoded, which is encoding, not encryption. Anyone with the token can read the payload. If you need encrypted tokens, look into JWE (JSON Web Encryption), which encrypts the payload so it cannot be read without a decryption key.

How long should a JWT access token last?

5-15 minutes is the widely accepted range for access tokens. Shorter is more secure. Longer is more convenient. For high-security applications (banking, healthcare), lean toward 5 minutes. For standard applications, 15 minutes is a reasonable balance.

What happens if someone steals a JWT?

They can impersonate the user until the token expires. This is why short expiration times matter. With a 15-minute token, the window of vulnerability is small. With a 30-day token, it is a disaster. Combine short-lived tokens with refresh token rotation to minimize damage.

Should I build my own JWT implementation?

No. Use a well-maintained library for your language (jsonwebtoken for Node.js, PyJWT for Python, etc.). JWT has subtle security pitfalls that are easy to get wrong: algorithm confusion attacks, timing attacks on signature verification, and improper key handling. Established libraries handle these correctly.