← Back to blog

JWT Explained for Developers: 15 Minute Token Defaults & Verification

September 16, 2026
JWT Explained for Developers: 15 Minute Token Defaults & Verification

A JWT is a compact, digitally signed JSON token defined by RFC 7519, built from three base64url-encoded parts separated by periods: header, payload, and signature. The signature proves the token hasn't been altered since it was issued, but it doesn't hide anything inside it. Anyone with the token can read the payload, so the real rule of thumb is simple: keep access tokens short-lived, never stuff them with secrets, and validate every claim before you trust them.


TL;DR:

  • Keep JWTs short-lived with expiration times between 5 and 60 minutes, and always pair them with a securely stored, rotating refresh token.
  • Validate the token's structure, signature, and claims thoroughly during verification, including matching aud, iss, and allowed algorithms explicitly.
  • Store tokens in HttpOnly cookies instead of localStorage to prevent XSS attacks, and never rely on the token's alg field without strict allowlists.
  • Use JWKS endpoints for signing key management, rotating keys with overlaps, and treat key rotation like production infrastructure to avoid verification failures.
  • Avoid putting sensitive data in payload claims, and build a revocation path with token blacklists or session counters to handle instant invalidation if needed.

Pingfloat
Validate Your JSON Faster
Pingfloat’s developer tools include JSON validation utilities for checking structured data while you troubleshoot authentication and web systems.
Visit Pingfloat

Table of Contents

What's Inside a JWT? Header, Payload, and Signature

Decode a JWT and you'll find three chunks separated by dots. The first two, the header and payload, are just base64url-encoded JSON. That's encoding, not encryption, so anyone holding the token can read both sections without a key. Only the third part, the signature, requires cryptographic verification.

The header carries metadata: alg (the signing algorithm, like RS256 or HS256), typ (usually "JWT"), and often kid (a key ID pointing to which public key to use). RFC 8725 pushes implementers to use typ explicitly whenever multiple token kinds coexist in a system, so a refresh token can't be mistaken for an access token.

The payload holds claims. RFC 7519 standardizes a handful worth knowing:

  • iss (issuer): who created the token
  • sub (subject): who the token represents
  • aud (audience): who the token is meant for
  • exp and iat (expiration and issued-at timestamps)
  • jti (a unique token ID, useful for revocation lists)

Custom claims are fine for roles or permissions, but RFC 7519 warns against putting anything sensitive in there, since the payload sits in plain view in logs, browser storage, and network traces. Before you even verify a signature, a quick sanity check helps: does the token have exactly two dots, does the header list an algorithm you actually expect, and does the payload decode into valid JSON?

How Do JWTs Work in Login and API Flows?

A JWT's job starts the moment a user authenticates. Understanding how it moves through a system matters as much as knowing its structure.

  1. Issue on login. The server (or an identity provider using OpenID Connect) issues an ID token describing who the user is, and often a separate access token describing what they're allowed to do. These serve different purposes even though both are JWTs.
  2. Client usage. Most APIs expect the access token in an Authorization: Bearer <token> header. Cookies are an alternative, and they carry different trade-offs: cookies can be marked HttpOnly to block JavaScript access, but they open the door to CSRF concerns that bearer headers avoid.
  3. Refresh. Because access tokens are short-lived by design, a longer-lived refresh token issues new ones without forcing a re-login. Refresh tokens are usually stateful, meaning the server tracks and can revoke them, unlike the stateless access token.
  4. Rotation. Each time a refresh token is used, a well-built system issues a new one and invalidates the old, limiting the damage if a refresh token leaks.

Watch where tokens travel. They end up in server logs, browser history if someone mistakenly appends one to a URL, and sometimes in proxy or CDN logs. None of those are places a bearer token should ever sit exposed.

When Should You Use JWTs Instead of Sessions?

JWTs shine when multiple independent services need to verify a caller without querying a central database. A microservices architecture where each service holds the issuer's public key, a single sign-on setup spanning several apps, or a stateless REST API serving mobile and web clients all fit that model well.

Traditional server-side sessions still win in other cases:

  • You need to revoke access the instant something goes wrong, not just wait for expiration.
  • Your session needs to hold a large amount of state that's expensive to repeat in every request.
  • Your architecture is a single monolith with one database, where a session lookup costs nothing extra.

A short decision test: if instant, hard revocation is a hard requirement, lean sessions. If you're verifying across services or third parties without a shared database, lean JWT.

What Security Practices Actually Prevent JWT Attacks?

Most JWT breaches trace back to a handful of repeatable mistakes, and OWASP's guidance on the topic keeps pointing at the same three: tokens that live too long, tokens stored somewhere JavaScript can read them, and code that trusts the algorithm named inside the token itself.

JWT security safeguards shown as three lanes

That last one deserves attention. Verification libraries should be told explicitly which algorithms are acceptable, never read the alg field from the token and use whatever it says. Attackers exploit this through algorithm confusion, tricking a server expecting RS256 into accepting a token signed with a weaker or forged method, or through the classic alg: none bypass, documented by PentesterLab, which some early libraries would accept as an unsecured token with no signature at all.

Beyond algorithm pinning, a few defaults matter most:

  • Keep access tokens short: OWASP recommends lifetimes commonly between 5 and 60 minutes.
  • Pair short access tokens with a stateful, rotating refresh token stored in an HttpOnly cookie.
  • Fetch signing keys from a JWKS endpoint, cache them, and rotate keys with an overlap window at least as long as your access token's TTL.
  • Build a revocation path even for "stateless" tokens, whether that's a jti blocklist or a per-user session counter you can bump to invalidate everything at once.

Pro Tip: Treat your JWKS endpoint like production infrastructure, not an afterthought. A botched key rotation without an overlap window will silently fail every verification request the moment the old key drops, and you'll be debugging 401 errors under pressure.

If your JWTs cross into certificate territory, such as mutual TLS setups paired with token-based auth, the operational discipline around rotating SSL certificates follows the same overlap logic: never let the old credential expire before the new one is fully live.

How Do You Validate a JWT Correctly?

Validation and verification aren't the same thing, and skipping steps is how forged tokens slip through. A middleware function checking a JWT should run through this sequence every time:

  1. Confirm the token has exactly three dot-separated parts, matching the compact serialization RFC 7519 requires.
  2. Base64url-decode the header and payload, confirming both parse as valid JSON.
  3. Look up the signing key by kid from your JWKS (or use a pinned public key), then verify the signature using only the algorithms your service explicitly allows.
  4. Check exp and nbf against the current time with a small clock skew allowance (a few seconds), confirm iss and aud match what you expect, check typ if your system issues multiple token kinds, and optionally check jti against a revocation list.

Skip step 3's algorithm restriction and you've reopened the door to algorithm confusion. Skip step 4's aud check and a token meant for one service could get accepted by another.

What Does a Decoded JWT Actually Look Like?

A compact JWT looks like gibberish until you split it on the dots. A header segment decodes to something like {"alg":"RS256","typ":"JWT","kid":"2026-01"}, and the payload might decode to {"sub":"user_882","iss":"auth.example.com","aud":"api.example.com","exp":1795000000,"iat":1794996400}. Nothing there is encrypted, it's just base64url math anyone can reverse.

Verification pseudo-code should look explicit, never implicit:

  • Fetch the key set from the issuer's JWKS URL and cache it.
  • Call verify(token, keys, { algorithms: ["RS256"] }), naming the algorithm rather than trusting the token's own header.
  • Reject anything that doesn't match, log the failure reason, and move on.

That example is illustrative, not production code. Always lean on a maintained, vetted library for your language rather than hand-rolling signature verification. When you just want to eyeball a token's claims while debugging, Pingfloat's JWT Decoder will split it into header and payload instantly, and the JSON formatter cleans up the decoded output for easier reading.

What Mistakes Break JWT Security Most Often?

The same handful of anti-patterns show up across breach postmortems and audits:

  • Long-lived access tokens with no revocation path. Fix it with short TTLs plus a rotating refresh token instead of one token that lives for days.
  • Storing tokens in localStorage. It's readable by any script on the page, making it an easy target for XSS. HttpOnly cookies, or in-memory storage with silent refresh, close that gap.
  • Trusting the token's own alg or an unchecked jku URL. Both let an attacker dictate how their forged token gets verified. Pin algorithms and allowlist key URLs.
  • Leaving library defaults unaudited. Many JWT libraries ship permissive defaults for backward compatibility. Read the configuration docs before shipping.

An Editorial Take on Safe JWT Defaults

Most teams overthink JWT security in the wrong direction, debating algorithms while shipping access tokens that live for a week. My recommended baseline: 15 minute access tokens, an HttpOnly refresh cookie with rotation, hard algorithm pinning, and a JWKS setup with real key rotation. Watch usage patterns and have a revocation plan ready before you need it, not after. Pingfloat's tools, including the JWT Decoder, exist to make that verification work easier to inspect.

— Andreas

Debug Tokens Faster With Pingfloat's Free JWT Decoder

Reading a JWT shouldn't require writing a script every time you need to check a claim. Pingfloat's JWT Decoder splits any token into its header and payload instantly, right in the browser, at no cost, so you can confirm an exp value or spot a misconfigured aud claim in seconds instead of firing up a debugger.

Pingfloat

Pair it with the JSON formatter when a decoded payload needs cleaning up, or the response headers inspector when you're tracking down whether a token is leaking somewhere it shouldn't. All three sit inside Pingfloat's free suite of developer tools, alongside SSL checks and uptime monitoring for the rest of your stack. Paste your next token into the decoder and see exactly what your API is issuing.

Sources

FAQ

Can You Explain JWT in Simple Terms?

A JWT is a signed piece of text containing claims about a user or session, split into a header, payload, and signature, all readable by decoding but only trustworthy once the signature is verified.

What's the Difference Between JWT and OAuth?

JWT is a token format, while OAuth is an authorization framework that defines how tokens get issued and used; OAuth flows commonly produce JWTs as access or ID tokens, but OAuth can also issue opaque, non-JWT tokens.

Are JWTs Still Widely Used?

Yes. JWTs remain a standard choice for stateless APIs, single sign-on, and OpenID Connect ID tokens, particularly in microservices architectures where multiple services need to verify a token independently.

What Is JWT Authentication and How Does It Work?

JWT authentication issues a signed token after login, which the client then sends with each request, typically in an Authorization: Bearer header, so the server can verify the signature and claims without a database lookup on every call.