env.dev

What is a JWT? A Developer Guide to JSON Web Tokens

Learn how JSON Web Tokens work — header, payload, and signature structure, typical auth use cases, common pitfalls, and best practices for secure usage.

Last updated:

A JSON Web Token (JWT) is a compact, URL-safe token used to securely transmit information between parties. It is most commonly used for authentication — once a user logs in, the server issues a JWT that the client sends with every subsequent request. The format is standardised in RFC 7519 (May 2015) and built on top of JWS (RFC 7515) and JWA (RFC 7518).

What are the three parts of a JWT?

A JWT is three Base64URL-encoded parts separated by dots:

text
header.payload.signature

Header

Specifies the token type (JWT) and the signing algorithm (e.g. HS256, RS256).

json
{ "alg": "HS256", "typ": "JWT" }

Payload

Contains claims — statements about the user and metadata. Standard claims include sub (subject), iat (issued at), and exp (expiry).

json
{ "sub": "user_123", "role": "admin", "exp": 1735689600 }

Signature

Created by signing the encoded header and payload with a secret (symmetric) or private key (asymmetric). This prevents tampering.

text
HMACSHA256(base64url(header) + "." + base64url(payload), secret)

How does JWT authentication work?

  1. User sends credentials to the server
  2. Server validates and returns a signed JWT
  3. Client stores the JWT (memory, localStorage, or httpOnly cookie)
  4. Client sends the JWT in the Authorization: Bearer <token> header
  5. Server verifies the signature on every request — no session lookup needed

What are the standard JWT claims?

RFC 7519 reserves seven claim names. The full list is maintained in the IANA JWT claim registry. Verifiers should validate iss, aud, and exp on every request.

ClaimNamePurpose
issIssuerWho minted the token (e.g. "https://auth.example.com")
subSubjectWho the token is about — usually the user ID
audAudienceWho the token is for — reject if your service is not in this list
expExpiryUnix seconds; reject after this time (must validate)
nbfNot beforeUnix seconds; reject before this time
iatIssued atUnix seconds when the token was minted
jtiJWT IDUnique token identifier — used for replay protection and blocklists

Which JWT signing algorithm should you use?

AlgorithmTypeUse case
HS256Symmetric (HMAC)Single-service auth, shared secret
RS256Asymmetric (RSA)Multi-service, public key verification
ES256Asymmetric (ECDSA)Compact keys, mobile/IoT

Performance matters at scale: HS256 verification is ~30 µs; RS256 is ~1.2 ms — roughly 40× slower because RSA is asymmetric. ES256 sits in the middle at ~200 µs and produces 64-byte signatures vs RSA-2048's 256 bytes. Pick HS256 when one service mints and verifies; pick RS256 or ES256 when verifiers must not hold the signing key (multi-service, public APIs, OIDC).

How do you verify a JWT in code?

Always verify the signature, the algorithm, the issuer, and the audience. The jose library (Node, browsers, Workers, Deno, Bun) is the safest choice in JavaScript:

typescript
import { jwtVerify } from 'jose';

const secret = new TextEncoder().encode(process.env.JWT_SECRET);

const { payload } = await jwtVerify(token, secret, {
  issuer: 'https://auth.example.com',
  audience: 'api.example.com',
  algorithms: ['HS256'],
});

console.log(payload.sub);

In Python, use PyJWT:

python
import jwt

payload = jwt.decode(
    token,
    secret,
    algorithms=['HS256'],
    issuer='https://auth.example.com',
    audience='api.example.com',
)

print(payload['sub'])

What is the access token vs refresh token pattern?

Because JWTs are stateless, you cannot revoke one before it expires — so issue them with short lifetimes and pair them with a long-lived refresh token:

  • Access JWT — short-lived (15 minutes is typical), sent on every API request in the Authorization header.
  • Refresh token — long-lived (7–30 days), opaque random string stored server-side, kept in an HttpOnly; Secure; SameSite=Strict cookie. The client posts it to /auth/refresh to mint a new access JWT.
  • Refresh tokens live in your database so you can revoke them on logout, password change, or suspected compromise. Access JWTs stay stateless.

What are the most common JWT pitfalls?

  • Do not store sensitive data in the payload. The payload is only Base64URL-encoded, not encrypted — anyone can decode it.
  • Always verify the signature server-side. Never trust a JWT that hasn't been verified.
  • Set an expiry (exp). Without it, a stolen token is valid forever.
  • Beware of the alg: none attack. Libraries that accept unsigned tokens are vulnerable (CVE-2015-9235, CVE-2016-10555). Always pin the expected algorithm — pass algorithms: ['HS256'] or similar to your verifier.
  • Revocation is hard. JWTs are stateless — you can't invalidate one without a blocklist. Use short expiries and refresh tokens for sensitive apps.

See also: JWT best practices for the full RFC 8725 checklist (key entropy, audience binding, explicit typing, replay protection).

References

Try the tools: JWT Debugger to inspect and decode tokens, or the JWT Generator to mint signed tokens for testing.

Was this helpful?

Read next

JWT Best Practices: Storage, Algorithms & Revocation

Security best practices for JSON Web Tokens: algorithm selection, storage, expiration, refresh patterns, revocation, and common vulnerabilities.

Continue →

Frequently Asked Questions

Is it safe to decode a JWT in the browser?

Yes. The header and payload of a JWT are just Base64URL-encoded JSON — they are not encrypted. Decoding reveals the claims but does not compromise security. The signature is what protects the token from tampering.

What are the three parts of a JWT?

A JWT has three Base64URL-encoded parts separated by dots: the header (algorithm and type), the payload (claims like sub, exp, iat), and the signature (cryptographic proof that the token was not tampered with).

What is the difference between JWT and session-based auth?

Sessions store state on the server (typically in a database or memory). JWTs are stateless — the token itself contains all the information the server needs. JWTs scale better horizontally but cannot be revoked without additional infrastructure.

Should I store JWTs in localStorage or cookies?

HttpOnly cookies are generally safer because they are not accessible to JavaScript, protecting against XSS attacks. localStorage is simpler but vulnerable to XSS. For most web applications, HttpOnly cookies with the Secure and SameSite flags are recommended.

Stay up to date

Get notified about new guides, tools, and cheatsheets.