What is a JWT?
A JSON Web Token (JWT, pronounced "jot") is an open standard (RFC 7519) for securely transmitting claims between two parties as a compact, URL-safe string. JWTs are most commonly used for authentication — once a user logs in, the server issues a JWT that the client sends with every subsequent request. The server verifies the token without needing to look up a session in a database.
Structure of a JWT
A JWT consists of three Base64URL-encoded parts separated by dots:
xxxxx.yyyyy.zzzzz
Header.Payload.Signature
1. Header
The header is a JSON object specifying the token type and the signing algorithm:
{
"alg": "HS256",
"typ": "JWT"
}
Common algorithms: HS256 (HMAC-SHA256, symmetric), RS256 (RSA-SHA256, asymmetric), ES256 (ECDSA-P256, asymmetric).
2. Payload
The payload contains claims — statements about the user or any other entity. There are three categories:
- Registered claims — standardised, short-named fields:
iss(issuer),sub(subject/user ID),aud(audience),exp(expiry as Unix timestamp),iat(issued-at),nbf(not-before),jti(JWT ID / unique identifier). - Public claims — agreed-upon custom claims registered in the IANA JWT Claims Registry.
- Private claims — application-specific claims shared between issuer and consumer, e.g.
role,email,tenantId.
{
"sub": "user_12345",
"email": "[email protected]",
"role": "admin",
"iat": 1704067200,
"exp": 1704153600
}
Important: the payload is only Base64URL-encoded, not encrypted. Anyone who has the token can decode and read the claims. Never put sensitive information (passwords, credit card numbers, secrets) in a JWT payload unless you also encrypt it (JWE).
3. Signature
The signature ensures the token has not been tampered with. It is computed by taking the encoded header, a dot, the encoded payload, and signing them with the secret (for HS256) or private key (for RS256/ES256):
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
When the server receives a token, it recomputes the signature and compares it to the one in the token. If they match, the token is valid and unmodified.
How JWT authentication works
- User sends credentials (username + password) to the login endpoint.
- Server validates credentials and issues a signed JWT.
- Client stores the JWT (typically in memory or
localStorage) and sends it in theAuthorizationheader on every API request:Authorization: Bearer <token>. - Server receives the token, verifies the signature, checks
exp, and reads the claims — no database lookup needed. - When the token expires, the client uses a refresh token to obtain a new JWT.
HS256 vs RS256 — which to use?
HS256 uses a single shared secret. Both the issuer and verifier must know the same secret. Simple to set up, but every service that needs to verify tokens must have the secret, which increases exposure.
RS256 uses a public/private key pair. The issuer signs with the private key; any consumer verifies with the public key. The private key never leaves the auth server, making this the right choice for microservices and third-party integrations. RS256 is the industry standard for production systems.
Common JWT security pitfalls
- The "alg: none" attack — an attacker removes the signature and sets the algorithm to
none, hoping the server accepts unsigned tokens. Always explicitly whitelist allowed algorithms on the server side. - Algorithm confusion — an attacker switches from RS256 to HS256 and signs with the public key (which is not secret). The server, if not checking the algorithm carefully, may accept it. Use a strict algorithm allowlist.
- Storing JWTs in localStorage — vulnerable to XSS attacks. Consider storing access tokens in memory and refresh tokens in HttpOnly cookies.
- Long expiry — a stolen token with a 30-day expiry is a serious risk. Keep access tokens short-lived (15 minutes) and use refresh tokens for session continuity.
- No token revocation — JWTs are stateless, so you cannot invalidate one before it expires without a blocklist. Design your system with short-lived access tokens to limit exposure.
JWT vs session cookies
Both are valid authentication mechanisms, and the right choice depends on your architecture:
- Use JWT for stateless APIs, microservices, mobile apps, and third-party token issuance (OAuth 2.0 / OpenID Connect).
- Use session cookies for traditional server-rendered web apps where you control both the client and server, and you need the ability to instantly invalidate a session.