JWT authentication uses a cryptographically signed JSON payload to securely transmit identity and authorization data between systems. The token is verified by the server without needing to store session state, enabling stateless authentication across distributed services.
When a user logs in, the server generates a JWT containing claims-such as user ID, role, and expiration time-and signs it with a secret key or private key. The client stores this token and sends it in the Authorization header of subsequent requests. The server validates the signature and checks the claims before granting access.
This method avoids storing session data on the server, reducing database load and simplifying scaling. It's widely used in APIs, mobile apps, and microservices architectures where maintaining session state across multiple servers is impractical.
The process begins when a client submits valid credentials-typically a username and password-to an authentication endpoint. The server verifies these against stored data, such as a hashed password in a database.
If the credentials match, the server creates a JWT. This token consists of three parts separated by dots: header, payload, and signature. The header declares the algorithm used (e.g., HS256 or RS256). The payload contains claims-standard ones like exp (expiration), iat (issued at), sub (subject), and custom ones like role or permissions.
The server then signs the encoded header and payload using a secret key (for HMAC algorithms) or a private key (for RSA). The resulting string is sent to the client as a single token.
A typical JWT looks like this: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIsImV4cCI6MTUxNjI0MDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c.
Breaking it down:
{"alg":"HS256","typ":"JWT"}{"sub":"1234567890","name":"John Doe","iat":1516239022,"exp":1516240000}On each protected request, the client includes the token in the Authorization header: Bearer <token>. The server decodes the token, verifies the signature, and checks if the token has expired or if required claims are present.
If validation passes, the server processes the request. If not, it returns a 401 Unauthorized error. This entire flow happens without the server needing to look up session data.
JWTs are used in various scenarios based on their security model and intended lifespan.
| Type | Signing Method | Use Case | Security Notes |
|---|---|---|---|
| Stateless Auth | HMAC-SHA256 (secret key) | Single-domain APIs, internal services | Fast but requires shared secret across services |
| Public Key Signing | RS256 (private/public key pair) | Multi-party systems, OAuth2 providers | Supports delegation; keys can be rotated |
| Refresh Tokens | HS256 or RS256 | Long-lived sessions with short-lived access tokens | Stored securely; not sent on every request |
For example, a mobile app might receive a JWT upon login with a 15-minute expiry. After that, the app uses a refresh token (also a JWT) to obtain a new access token without re-entering credentials.
One non-obvious point: JWTs are not inherently secure. They're only as safe as the signing key and how they're handled. Sending a JWT in a URL parameter exposes it to logging and browser history. Always use HTTPS and avoid storing tokens in localStorage unless properly secured.
JWT authentication is often mistaken for session cookies. While both authenticate users, cookies store session identifiers on the server and rely on server-side storage. JWTs carry all necessary data in the token itself.
Another confusion arises with OAuth2. JWTs are frequently used *within* OAuth2 flows-especially in OpenID Connect-but they are not the same. OAuth2 defines the authorization structure; JWTs are one way to represent identity tokens within that structure.
For instance, Google's OAuth2 service issues ID tokens in JWT format. These are validated by the client using Google's public keys. The client doesn't store session state-it just checks the token's validity and extracts user info.
Consider a weather API that requires authentication. A user logs in via POST /auth/login with credentials:
{
"email": "[email protected]",
"password": "securepass"
}
The server responds with a JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNTE2MjM5MDIsImV4cCI6MTUxNjI0MDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
The client saves this token and sends it on every request:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNTE2MjM5MDIsImV4cCI6MTUxNjI0MDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
The server validates the signature using the shared secret. If valid and not expired, it returns weather data. If invalid or expired, it denies access.
I've implemented this flow in a Node.js backend using the jsonwebtoken library. The token generation took under 10 lines of code. The validation was equally straightforward. What surprised me was how quickly performance improved-no database lookup per request, even under high load.
Never treat JWTs as immutable trust. Always validate the signature, check the expiration time, and verify required claims. Set short expiration times-15 to 30 minutes-for access tokens.
Store refresh tokens securely, preferably in HTTP-only cookies. Avoid sending JWTs in URLs or browser history. Use HTTPS exclusively to prevent interception.
According to OWASP, improper handling of JWTs is a top-10 web application risk. Misconfigured algorithms (like using "none" for signing) or weak secrets can lead to token forgery.
Use tools like jwt.io to inspect and decode tokens during debugging. But never send sensitive tokens to untrusted sites.
For long-term access, consider implementing token revocation mechanisms-even though JWTs are stateless, you can maintain a blacklist of revoked tokens in a fast cache like Redis.
Understanding how JWT authentication works enables better design decisions in secure systems. It's not just a login mechanism-it's a foundation for scalable, secure identity exchange across services.