Developer guide

How to inspect a JWT safely without confusing decoding with verification

JWTs are usually readable by design, but their contents can still be sensitive. A safe inspection workflow keeps tokens local and separates decoding, signature verification, claim validation, and authorization.

Key takeaways

  • Decoding a JWT shows its header and claims; it does not prove that the issuer signed it or that an application should accept it.
  • Treat bearer tokens like credentials even when the payload contains no obvious secret.
  • Validation must check the signature, permitted algorithm, issuer, audience, time claims, and application-specific authorization rules.

A JSON Web Token commonly appears as three dot-separated segments:

header.payload.signature

The header and payload usually contain Base64URL-encoded JSON. Encoding makes binary-safe transport convenient; it does not encrypt the content. Anyone holding the token can generally decode those two segments.

That creates two opposite mistakes. Some people paste production tokens into random decoder websites because the content appears harmless. Others assume that a readable, well-formed token must be valid. Both conclusions are unsafe.

What the three segments mean

The header describes how the token is represented and commonly names a signing algorithm. The payload contains claims. The signature is calculated by the issuer and is intended to let a verifier detect unauthorized changes.

An illustrative payload might contain:

{
  "iss": "https://identity.example.test",
  "aud": "inventory-api",
  "sub": "user-123",
  "iat": 1787788800,
  "nbf": 1787788800,
  "exp": 1787792400,
  "scope": "inventory.read"
}

This example uses fictional values. A real token may include email addresses, tenant identifiers, roles, scopes, session identifiers, or internal system names. Even without a password, those details can be sensitive. A bearer access token may also grant access to whoever possesses it until it expires or is revoked.

A safer local inspection workflow

Use JWT Decoder to inspect the segments inside the current browser tab. The tool interprets common time claims and does not intentionally send the token to an application backend.

Before pasting a token anywhere:

  1. Prefer a token from a development environment with synthetic identities.
  2. If production inspection is unavoidable, understand that the entire token is a credential, not merely JSON.
  3. Confirm that the decoder operates locally and does not place the token in a URL, analytics event, or remote request.
  4. Clear the interface after inspecting it.
  5. Revoke or rotate an exposed token according to the identity provider’s procedure.

Browser-local processing reduces disclosure to a third-party processing service. It does not protect against a compromised device, malicious extension, screen recording, clipboard history, or someone with access to the browser session.

Decoding is not signature verification

A decoder can parse a token whose signature is invalid, missing, created by the wrong issuer, or produced with an algorithm the application should reject. Readable claims answer “what does this string say?” They do not answer “who created it?” or “should this request be authorized?”

Proper validation belongs in the application or trusted API receiving the token. It normally includes:

  • verifying the signature with the correct trusted key;
  • restricting accepted algorithms instead of trusting the header blindly;
  • checking iss against the expected issuer;
  • checking aud against the intended application or API;
  • enforcing exp and, when present, nbf;
  • applying an intentional clock-skew policy;
  • validating tenant, scope, role, session, or token-version rules;
  • making an authorization decision for the requested resource.

Even a cryptographically valid token can be inappropriate for a particular API, tenant, operation, or user session.

Understanding time claims

JWT time claims use NumericDate values: seconds since the Unix epoch. The three common claims are:

  • iat: when the token was issued;
  • nbf: the earliest time at which it should be accepted;
  • exp: the expiration time after which it should be rejected.

Use Unix Timestamp Converter when you need to compare a value in UTC and local time. Be careful about milliseconds: JavaScript timestamps often use milliseconds, while JWT NumericDate values use seconds.

An unexpired exp does not prove validity. It only means the time condition may be satisfied. Signature, issuer, audience, and authorization checks remain necessary.

Base64URL is not ordinary Base64

JWT segments use the URL-safe Base64 alphabet and usually omit padding. A generic Base64 Encoder / Decoder can help explain the encoding, but a JWT-aware decoder is preferable because it handles the URL-safe substitutions and token structure.

Formatting the decoded payload with JSON Formatter can make nested custom claims easier to review. Never edit the displayed JSON and assume the original token changed; changing a payload requires producing an entirely new, correctly signed token.

What to record in a bug report

Avoid attaching a complete active token. Prefer a sanitized claim summary:

  • issuer and audience;
  • algorithm name;
  • issue and expiration times;
  • relevant scopes or roles with personal identifiers removed;
  • the validation error;
  • a correlation identifier that is safe to share.

If reproducing the exact token is essential, use a secure internal channel with limited retention and revoke the token afterward. A screenshot with the signature blurred is not necessarily safe if the visible header and payload still contain identifying information.

The central rule is straightforward: decode locally for understanding, verify in a trusted security boundary, and authorize against the actual operation.