🔑
Developer Tools
February 21, 20268 min readBy SoftStash Team

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.

JWTauthenticationtokenOAuthsecuritydeveloper

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 alg to "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

ClaimFull nameDescription
issIssuerWho issued the token (e.g., your auth server URL)
subSubjectWho the token is about — typically the user's unique ID
audAudienceWhich service(s) the token is intended for
expExpiration TimeUnix timestamp after which the token must be rejected
iatIssued AtUnix timestamp of when the token was created
nbfNot BeforeToken is not valid before this Unix timestamp
jtiJWT IDUnique 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.

Security warning — payload is not encrypted: The JWT payload is Base64URL-encoded, not encrypted. Anyone who has the token string can decode the header and payload without any key or secret. Never store sensitive information in a JWT payload — no passwords, payment card data, social security numbers, or private keys. Treat the payload as public-readable data that is merely tamper-evident, not confidential.

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.
Critical security rule: Always verify JWT signatures server-side using a trusted key. Never rely on client-side verification alone. A client can decode the payload of any JWT without a secret — but only the server, holding the correct key, can determine whether the signature is genuine and the token can be trusted. Client-side decoding is only useful for reading claims (like showing the user's name in a UI), never for making authorization decisions.

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.

Your tokens stay private: JWT tokens frequently contain user IDs, email addresses, roles, and other personal data. The SoftStash JWT Decoder processes your token entirely in your browser — it is never sent to any server, never logged, and never stored. You can safely paste production tokens to inspect them without worrying about exposure. Once you close the tab, it is gone.

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 →