Abstract three-part JWT token segments connected by dots on a dark navy background
JWT authenticationJSON Web TokenJWT explainedaccess tokenrefresh tokenAPI securityOAuthBearer token

JWT Authentication Explained: How JSON Web Tokens Work

JWT authentication explained for APIs and SPAs: how JSON Web Tokens work, access vs refresh tokens, secure storage, common pitfalls, and a production checklist - without the hand-wavy diagrams.

Swati ChaudharyFounder, Myrafy

JWT authentication (JSON Web Tokens) is how most modern APIs prove "this request is from a logged-in user" without looking up a session on every call.

A JWT is a signed, Base64URL-encoded string with three parts: header.payload.signature. The server issues it after login; the client sends it as a Bearer token. Anyone can decode the payload - only someone with the signing key should be able to forge a valid signature.

This guide explains JWT authentication the way we implement it for product APIs and Next.js apps: structure, access vs refresh, storage choices, and the mistakes that cause real breaches.

Decode and inspect tokens safely in the browser with Myrafy's free JWT Decoder (no signature verification - never paste production secrets). To sketch claims and expiry, use the JWT Builder.

What Is a JSON Web Token?

JWT structure showing header, payload claims, and signature segments
Header, payload, and signature make a JWT

A JWT looks like:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NSIsImV4cCI6MTcwMDAwMDAwMH0.signature
Part Contains Public?
Header Algorithm (HS256, RS256, ...) and type Yes (Base64URL)
Payload Claims: sub, exp, iat, roles, tenant Yes - not encrypted
Signature HMAC or asymmetric signature over header+payload Verifiable with key/secret

Important: JWTs are signed, not secret by default. Do not put passwords, API keys, or PII you cannot afford to leak into the payload. Treat claims as visible to anyone who holds the token.

How JWT Authentication Works (Login โ†’ Request)

Typical flow for a SPA or mobile app:

  1. User submits credentials (or OAuth code) to your auth service
  2. Server verifies identity, then issues an access token (short-lived JWT) and often a refresh token
  3. Client sends Authorization: Bearer <access_token> on API calls
  4. API verifies signature, exp, issuer (iss), audience (aud), and authorization claims
  5. When the access token expires, the client uses the refresh token to get a new access token - or re-login

Stateless access tokens scale well: any API instance can verify the signature without a shared session store. You still need revocation strategy for logout, stolen tokens, and password resets (denylist, short TTL, or rotating refresh tokens).

Access Tokens vs Refresh Tokens

Access token (JWT) Refresh token
Lifetime Minutes (e.g. 5-15) Days/weeks, or until rotated
Sent to Every protected API Auth/token endpoint only
Format Usually JWT Opaque string or JWT
Storage Memory preferred; careful with cookies HttpOnly Secure cookie preferred
Compromise impact Short window Full session until revoked

Rule: keep access tokens short. Put long-lived trust in refresh tokens with rotation and server-side storage (or a refresh-token family you can invalidate).

For browser apps, a common production pattern is:

  • Access token in memory (or short-lived HttpOnly cookie on same-site APIs)
  • Refresh token in HttpOnly, Secure, SameSite cookie
  • CSRF protection if cookies are used for auth

Avoid localStorage for long-lived tokens if XSS is in your threat model - and assume XSS is in your threat model for any non-trivial SPA.

Signing Algorithms: HS256 vs RS256 / ES256

Symmetric HMAC secret versus asymmetric public-key verification for JWT signatures
Choose HMAC for one service; prefer asymmetric keys for many verifiers

  • HS256 (HMAC): one shared secret. Simple for a single backend. Sharing the secret with every microservice is risky.
  • RS256 / ES256: private key signs; public key verifies. Better when many services verify tokens, or when you publish JWKS for partners.

In production:

  • Prefer asymmetric algorithms for multi-service APIs
  • Rotate keys with a kid in the header and a JWKS endpoint
  • Reject alg: none and unexpected algorithms (classic JWT attack class)

Claims You Should Actually Use

Minimum useful claims:

  • sub - stable user id
  • exp / iat - expiry and issued-at
  • iss / aud - issuer and intended audience
  • Optional: jti for denylist / one-time use
  • Optional: roles or scopes - keep them coarse; fine-grained auth still belongs in the API

Validate issuer and audience on every request. Signature alone is not enough if you accept tokens meant for another product.

Common JWT Authentication Mistakes

  1. Storing JWTs forever in localStorage - XSS steals the session
  2. No expiry (exp missing or months long) - stolen tokens live forever
  3. Sensitive data in the payload - JWTs are readable
  4. Trusting client-side decode only - always verify signature server-side
  5. Skipping refresh rotation - one stolen refresh = indefinite access
  6. Accepting alg: none or wrong key - library misconfiguration
  7. Using JWT for everything - high-churn permissions, instant revoke, or huge claims often need sessions or server lookups

Sessions vs JWT is not religion: use JWTs when stateless verification and horizontal scale matter; use server sessions when instant revoke and smaller cookies matter more.

Production Checklist

  • Short-lived access tokens; refresh with rotation
  • Verify signature + exp + iss + aud on the server
  • Algorithm allowlist (no none)
  • Secure cookie flags if cookies carry tokens
  • Logout / password-reset path that invalidates refresh tokens
  • Rate-limit login and refresh endpoints
  • Structured auth logging without dumping full tokens
  • HTTPS everywhere; HSTS on public sites

For SPA + API products built with Next.js, keep auth boundaries clear alongside Server Components: secrets and verification stay on the server; the browser only holds what it must. Signing keys and refresh-token stores belong in a proper secrets setup - the same discipline as a boring AWS DevOps baseline.

FAQ: JWT Authentication Explained

Is JWT authentication the same as OAuth? No. OAuth 2.0 / OIDC is a delegation framework. JWTs are a token format often used as access tokens (and ID tokens) inside those flows.

Can I revoke a JWT? A pure stateless JWT lasts until exp. For earlier revoke: short TTL, refresh-token denylist, or a jti denylist / version claim checked on each request.

Should microservices all share one JWT secret? Prefer asymmetric keys or a dedicated auth service issuing tokens; share verification material (JWKS), not a single HMAC secret with every team.

Are JWTs encrypted? Not by default. JWE exists for encryption; most APIs use signed JWTs (JWS) and treat the payload as public.

The Bottom Line

JWT authentication works when you treat tokens as short-lived, signed credentials - not as encrypted vaults or permanent session IDs. Issue carefully, verify strictly, store refresh tokens safely, and design for revoke.

Boring auth that is hard to forge beats clever tokens that are easy to steal.


Building a product API or Next.js app and need auth designed correctly the first time? See Myrafy software development services or contact us for an estimate.

Contact us