ToolHive

What Is a JWT and How to Decode One Safely

·4 min read

If you've worked with any modern web API, you've probably encountered a JWT. They show up as bearer tokens in HTTP Authorization headers, as the payload you get back from an OAuth flow, and as session tokens in browser cookies. They look like a wall of random characters, but they have a precise structure — and you can read them.

What a JWT Looks Like

A JWT is a string of three base64url-encoded parts joined by dots:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Split it at the two dots and you get three segments:

  1. Header — describes the token type and the signing algorithm used
  2. Payload — carries the claims (the actual data the token asserts)
  3. Signature — cryptographic proof the token was issued by a trusted authority and hasn't been tampered with

Decoding vs. Verifying — A Critical Distinction

These two operations are commonly confused, and the distinction matters for security.

Decoding means base64url-decoding the header and payload to turn them from opaque strings into readable JSON. This requires no key and no secret — anyone can do it. All you're doing is reversing the encoding.

Verifying means checking the signature to confirm the token was genuinely issued by the expected authority and hasn't been modified since. This requires the signing key: either the HMAC shared secret (for HS256, HS384, HS512) or the public key (for RS256, ES256, and other asymmetric algorithms).

The security implication is this: a decoded token is not a verified token. Anyone can construct a JWT with any payload they like. The signature is what proves legitimacy. If your server-side code accepts a JWT's claims without verifying the signature, an attacker can forge tokens for any user they choose.

Verification must always happen server-side, in your application code, using a secret or key you control. A browser-based decoder — including the one on ToolHive — is for inspection only. Never paste your signing secret into any online tool.

Reading the Header

Decode the first segment and you get JSON like this:

{
  "alg": "HS256",
  "typ": "JWT"
}
  • alg — the algorithm used to sign the token. HS256 is HMAC-SHA256 (symmetric, uses a shared secret). RS256 is RSA-SHA256 (asymmetric, uses a public/private key pair). ES256 uses elliptic curve cryptography.
  • typ — token type, almost always "JWT".

Reading the Payload

The payload holds claims — key-value pairs asserting facts about the subject or the token itself. Some claim names are standardized by the JWT spec (RFC 7519):

  • sub — subject: who the token is about, typically a user ID
  • iss — issuer: which service created the token
  • aud — audience: which service the token is intended for
  • exp — expiry: Unix epoch timestamp after which the token should be rejected
  • iat — issued at: when the token was created
  • nbf — not before: earliest time the token is valid

A decoded payload might look like:

{
  "sub": "user_8a3f12",
  "name": "Jane Doe",
  "email": "jane@example.com",
  "role": "admin",
  "iat": 1749996400,
  "exp": 1750000000
}

The exp field is a Unix timestamp (seconds since January 1, 1970 UTC). To check whether a token has expired, convert that number to a date and compare it to now. An expired token will still decode — it just shouldn't be accepted by a server doing proper validation.

What the Signature Segment Contains

The third segment is the raw signature bytes, base64url-encoded. It's computed from the header and payload using the signing key, and it changes if either part is modified. You can see the raw signature in a decoder, but you can't verify it without the key — and that's by design.

When You'd Want to Decode a Token

Even without verifying the signature, decoding is genuinely useful during development and debugging:

  • Checking what claims a token carries — is the role field present? Is the user ID format correct?
  • Confirming when a token expires by reading the exp claim
  • Debugging an OAuth flow where a downstream service is rejecting tokens — what does it actually contain?
  • Inspecting a token from a request to understand why a server returned a 401

In production systems, your library (jsonwebtoken, python-jose, go-jwt, etc.) handles both decoding and verification together. Manual decoding is for debugging and inspection.

Try It

If you have a token in your clipboard — from a browser DevTools network panel, an API response, or a .env file — paste it into the JWT Decoder on ToolHive to see the header and payload decoded instantly. Decoding happens locally in your browser using the built-in atob / Web Crypto APIs; nothing is sent to a server.

One quick tip: if a token looks malformed or the decoder returns an error, check for extra spaces or line breaks. Tokens copied from email clients or Slack sometimes get whitespace inserted around the dots.

Try the JWT Decoder

Decode and inspect JSON Web Tokens in your browser.

Open JWT Decoder

← Back to Blog