How to Decode and Verify JWT Tokens in Your Browser
JWT tokens are everywhere in modern authentication. Learn what they contain, how to decode them, spot expiry issues, and debug auth problems — all privately in your browser.
If you have worked with any modern web authentication system — OAuth 2.0, OpenID Connect, or a custom API — you have almost certainly encountered JWT tokens. They show up in Authorization headers, in cookies, in local storage, and in debugging sessions at 2 AM when a login flow is mysteriously failing. Understanding what a JWT actually contains, how to read it, and how to spot common problems makes authentication debugging dramatically faster.
The SoftStash JWT Decoder lets you paste any JWT token and instantly see its decoded header, payload, and expiry status — all in your browser, with the token never leaving your device.
What Is a JWT?
JWT stands for JSON Web Token, defined in RFC 7519. A JWT is a compact, URL-safe token that encodes a set of claims — assertions about a subject, typically a user — in a format that can be verified and trusted. The key property of a JWT is that it is self-contained: the token itself carries all the information a server needs to authenticate a request, without a database lookup.
A JWT looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfODQyMTkiLCJuYW1lIjoiSmFuZSBEb2UiLCJlbWFpbCI6ImphbmUuZG9lQGV4YW1wbGUuY29tIiwicm9sZXMiOlsidXNlciIsImVkaXRvciJdLCJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJhdWQiOiJodHRwczovL2FwaS5leGFtcGxlLmNvbSIsImlhdCI6MTczODM2ODAwMCwiZXhwIjoxNzM4MzcxNjAwLCJqdGkiOiI3ZjNhOWI0Yy0xZDJlLTQ1NmYtYWJjZC04OTAxMjM0NTY3ODkifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
At first glance it looks like gibberish. But it has a very precise structure: three Base64URL-encoded sections separated by dots. Each section has a specific purpose.
The Three-Part Structure: Header.Payload.Signature
Part 1: The Header
The first segment, before the first dot, is the header. It is a Base64URL-encoded JSON object describing the token's type and the signing algorithm. Decoded, the header from the example above looks like:
{
"alg": "HS256",
"typ": "JWT"
}The alg field specifies the signing algorithm. Common values you will encounter are:
- HS256 — HMAC with SHA-256. Uses a shared secret key. Both the issuer and verifier must have the same secret. Common in monolithic applications.
- RS256 — RSA signature with SHA-256. Uses a public/private key pair. The issuer signs with the private key; verifiers check with the public key. Common in distributed systems and OAuth providers.
- ES256 — ECDSA with P-256 and SHA-256. Like RS256 but using elliptic curves — shorter keys, same security level. Preferred in modern high-performance systems.
- none — No signature. Never accept this in production. A notorious security vulnerability arises when servers accept unsigned tokens because the client changed
algto"none".
Part 2: The Payload
The second segment is the payload — the actual data the token carries. It is also a Base64URL-encoded JSON object. The decoded payload from our example:
{
"sub": "usr_84219",
"name": "Jane Doe",
"email": "[email protected]",
"roles": ["user", "editor"],
"iss": "https://auth.example.com",
"aud": "https://api.example.com",
"iat": 1738368000,
"exp": 1738371600,
"jti": "7f3a9b4c-1d2e-456f-abcd-890123456789"
}The payload contains two types of claims: registered claims defined by the JWT specification, and private/custom claims added by your application (likename, email, and roles above).
Part 3: The Signature
The third segment is the signature. It is computed by taking the Base64URL-encoded header, a dot, the Base64URL-encoded payload, and signing the result with the algorithm and key specified in the header. For HS256:
HMAC-SHA256( base64url(header) + "." + base64url(payload), secret )
The signature ensures integrity: if anyone modifies even a single character in the header or payload after the token is issued, the signature becomes invalid and verification fails. Without knowing the signing secret (or the issuer's private key for RS256/ES256), an attacker cannot forge a valid token.
Standard JWT Claims Reference
| Claim | Full name | Description |
|---|---|---|
iss | Issuer | Who issued the token (e.g., your auth server URL) |
sub | Subject | Who the token is about — typically the user's unique ID |
aud | Audience | Which service(s) the token is intended for |
exp | Expiration Time | Unix timestamp after which the token must be rejected |
iat | Issued At | Unix timestamp of when the token was created |
nbf | Not Before | Token is not valid before this Unix timestamp |
jti | JWT ID | Unique identifier for the token — used to prevent replay attacks |
Why the exp Claim Is Critical
The exp claim is a Unix timestamp — the number of seconds since January 1, 1970 (UTC). In our example, "exp": 1738371600. To convert this to a human-readable date, you can use JavaScript:
new Date(1738371600 * 1000).toUTCString() // → "Sat, 01 Feb 2026 01:00:00 GMT"
JWT expiry is the first thing to check when a token is being rejected. A token that was valid yesterday will fail today if its exp is in the past — this is by design. Short-lived tokens (15 minutes to 1 hour) limit the window of damage if a token is stolen. Longer-lived tokens (days or weeks) are more convenient but more dangerous if compromised.
The SoftStash JWT Decoder automatically reads the exp and iat claims and displays them as human-readable dates alongside the raw Unix timestamps, so you never have to do the mental math manually.
Common JWT Debugging Scenarios
Token Expired (401 Unauthorized)
The most common JWT error. The server rejected the token because the current time is past theexp value. Fix: implement a token refresh flow using a longer-lived refresh token, or simply re-authenticate. Paste the token into the decoder to confirm exactly when it expired.
Wrong Audience
If your API validates the aud claim and the token was issued for a different audience (e.g., a token issued for https://api-staging.example.com being sent to https://api.example.com), the server will reject it. Decode the token and inspect theaud field to confirm it matches what the receiving service expects.
Algorithm Mismatch
If your server expects RS256 but receives a token signed with HS256 (or vice versa), validation fails. This can happen during key rotation or when switching auth providers. Check the alg field in the decoded header against what your server is configured to accept.
Signature Invalid
If the payload has been tampered with — even a single character changed — the signature will not match. This also happens if you are using the wrong secret or the wrong public key to verify. Decoding the header and payload (which requires no secret) lets you at least inspect what the token claims, even if you cannot verify its authenticity client-side.
JWT vs Session Tokens: When to Use Each
JWTs and traditional session tokens solve the same problem — identifying an authenticated user across multiple requests — but they do it differently, and neither is universally better.
Traditional session tokens are opaque random strings (e.g., a UUID) stored server-side in a session store (Redis, database). On each request the server looks up the token in the store and retrieves the user data. The server has full control: invalidating a session immediately revokes access.
JWTs are stateless. The server issues a signed token and does not keep a record of it. On each request the server verifies the signature and trusts the claims without any database lookup. This scales horizontally without shared state — any server with the verification key can authenticate the request. The tradeoff: you cannot immediately revoke a JWT before it expires (unless you implement a token blocklist, which reintroduces state).
- Use JWTs for stateless microservices, distributed systems, mobile APIs, and cross-domain authentication (OAuth/OIDC flows). Keep expiry times short.
- Use session tokens when you need immediate revocation capability (logout, account suspension, security incidents), or when all your services share a fast session store.
How to Use the SoftStash JWT Decoder
Open the JWT Decoder and paste your token into the input field. The tool immediately splits the token at the two dots and displays:
- Header panel: The decoded JSON showing
alg,typ, and any other header fields. Useful for identifying the signing algorithm at a glance. - Payload panel: The full decoded JSON with all claims. Timestamps are displayed in both raw Unix format and human-readable UTC dates so you can immediately see expiry without mental conversion.
- Expiry status: A clear indicator showing whether the token is currently valid, already expired, or not yet active (based on
nbf). If expired, you see exactly how long ago it expired. - Signature segment: The raw Base64URL-encoded signature, displayed for reference. The tool does not verify the signature (that requires the secret or public key), but it decodes and displays all the information you need for debugging.
There is no form submission, no server request, no clipboard access beyond what you explicitly paste. The token parsing happens entirely in JavaScript running in your browser tab.
Decode Your JWT Token Now
Whether you are debugging an expired token, inspecting claims from an OAuth provider, checking what roles a user has been granted, or simply trying to understand what your authentication system is actually issuing — the SoftStash JWT Decoder gives you the answers instantly. No registration, no extensions to install, no data sent anywhere.
Free JWT Decoder — Instant, Private, No Sign-Up
Open JWT Decoder →Try the Tools — 100% Free, No Sign-Up
Everything runs in your browser. No uploads. No accounts. No ads.
Explore All Tools →