A JSON Web Token (JWT) is a compact token that proves who you are. After you log in, the server creates a signed token containing your user ID, permissions, and expiration time. You send this token with every request. The server verifies the signature and knows who you are — without storing any session data.
If you have ever wondered what that long string of characters in your Authorization header is, or why your API uses "Bearer tokens," this is the explanation. No jargon, no unnecessary complexity — just how JWTs work in practice.
Think of a JWT like a tamper-proof wristband at a music festival:
That is JWT authentication. The token carries your identity. The signature proves it is authentic. The server is stateless.
A JWT is three Base64-encoded JSON objects separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzE3MDI3MjAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Decoded, the three parts are:
| Part | Decoded Content | Purpose |
|---|---|---|
| Header | {"alg":"HS256","typ":"JWT"} | Tells the server which algorithm was used to sign |
| Payload | {"sub":"1234567890","name":"John Doe","role":"admin","exp":1717027200} | The actual data — user identity and permissions |
| Signature | HMACSHA256(header + "." + payload, secret) | Proves the token was not modified and was issued by the trusted server |
Three common authentication methods, and when each makes sense:
| Feature | JWT (Bearer Token) | Session Cookie | API Key |
|---|---|---|---|
| State | Stateless — all data in the token | Stateful — session stored on server | Stateless — key is the credential |
| Storage | Client stores token (localStorage, cookie, memory) | Server stores session (Redis, DB, memory) | Client stores key (env var, config) |
| Scalability | \u2713 No shared state between servers | ~Requires shared session store across servers | \u2713 No shared state |
| Revocation | \u2717 Hard — token valid until expiration | \u2713 Easy — delete session from store | \u2713 Easy — delete key from database |
| Size | ~200-800 bytes (grows with claims) | ~32 bytes (just a session ID) | ~32-64 bytes |
| Cross-domain | \u2713 Works across domains (Authorization header) | \u2717 Cookies are domain-scoped | \u2713 Works across domains |
| Best for | APIs, microservices, mobile apps, SPAs | Traditional web apps, server-rendered pages | Server-to-server, third-party integrations |
| Security risks | Token theft, no revocation without infra | Session fixation, CSRF (mitigated with SameSite) | Key theft, no built-in expiration |
Here is the complete flow from login to authorized API request:
POST /auth/loginAuthorization: Bearer eyJhbG...| Claim | Name | Required? | What It Does |
|---|---|---|---|
| sub | Subject | Recommended | Identifies who the token is about (user ID) |
| iss | Issuer | Recommended | Identifies who created the token (your auth server URL) |
| aud | Audience | Recommended | Identifies who the token is for (your API URL) |
| exp | Expiration | Recommended | Unix timestamp when the token expires |
| iat | Issued At | Optional | Unix timestamp when the token was created |
| nbf | Not Before | Optional | Token is not valid before this timestamp |
| jti | JWT ID | Optional | Unique identifier — useful for one-time-use tokens |
Beyond these, you can add any custom claims: email, name, role, org_id, permissions, plan_tier — anything your application needs to know about the user without making a database call.
JWTs are not a universal authentication solution. They add complexity compared to session cookies for traditional web apps. They cannot be revoked without additional infrastructure (blacklists, short expiration + refresh tokens). They grow in size as you add claims, increasing bandwidth on every request. And they require careful security practices — algorithm validation, proper storage, signature verification. For simple web apps with server-side rendering, session cookies are often simpler and more secure. JWTs shine in distributed systems, APIs, and cross-domain authentication scenarios.
Decode any JWT right now — paste a token and see exactly what is inside.
Open JWT Decoder