JSON Web Tokens (JWTs) are a compact, self-contained method for securely transmitting authentication and authorization information between parties. This guide explains what JWTs are, how they work, and the best practices for using them safely in modern applications.
A JSON Web Token is an open standard (RFC 7519) that encodes a set of claims as a JSON object, then signs it so the receiver can verify its authenticity. A JWT consists of three Base64URL-encoded parts separated by dots: a Header, a Payload, and a Signature. The Header describes the token type and signing algorithm, the Payload carries claims (data), and the Signature proves the token has not been tampered with. Because all data lives inside the token itself, JWTs are called self-contained or stateless tokens.
Traditional session-based authentication stores session state on the server, which becomes difficult to scale across multiple servers or microservices. JWTs solve this by letting the server validate a token purely from the token's content and signature without querying a database or shared session store. This makes them ideal for distributed systems, single-page applications, and mobile apps. They also work naturally across domains, enabling use cases like single sign-on (SSO).
When a user logs in successfully, the server creates a JWT signed with a secret key (HMAC) or a private key (RSA/ECDSA) and sends it to the client. The client stores the token — typically in memory or an HTTP-only cookie — and attaches it to subsequent requests, usually in the Authorization header as a Bearer token. The server receives the request, verifies the signature, checks claims like expiration (exp), and grants or denies access without any session lookup. If the signature check fails or the token is expired, the server rejects the request immediately.
The Header JSON typically contains {"alg":"HS256","typ":"JWT"} encoded in Base64URL. The Payload contains standard claims such as sub (subject/user ID), iat (issued at), exp (expiration time), and any custom claims like roles or permissions. The Signature is computed as HMAC-SHA256(base64url(header) + '.' + base64url(payload), secret). Decoding the header and payload requires no secret, so never store sensitive data like passwords inside a JWT payload.
Never use the 'none' algorithm — some early libraries accepted it, allowing attackers to forge tokens with no signature. Always explicitly whitelist the expected algorithm on the server side rather than trusting the algorithm declared in the token header. Set short expiration times (e.g., 15 minutes) for access tokens and use refresh tokens to issue new ones, reducing the damage window if a token is stolen. Since JWTs cannot be invalidated before expiry without server-side state, plan for a token revocation strategy such as a short-lived deny-list when immediate logout is required.
Store JWTs in HTTP-only, Secure, SameSite cookies rather than localStorage to protect against XSS attacks. Always validate the exp, iss (issuer), and aud (audience) claims on every request to prevent token reuse across environments. Use asymmetric algorithms (RS256 or ES256) in multi-service architectures so only the auth server holds the private signing key while other services verify with the public key. Rotate signing keys periodically and implement a JWKS (JSON Web Key Set) endpoint so services can fetch current public keys automatically.
© RM Full Stack & AI Engineer · All guides · Roadmaps · Open the app