What is a JWT?
A JWT (JSON Web Token) is an open standard (RFC 7519) for securely transmitting information between parties as a JSON object. The information can be verified and trusted because it is digitally signed.
JWTs are most commonly used for:
- Authentication: After a user logs in, the server issues a JWT. The client presents this token on subsequent requests to prove identity without needing to query a database for every request.
- Information exchange: Parties can securely transmit claims (assertions about a user or session) in a way that can be verified by anyone with the public key.
A JWT looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Notice the two dots separating three segments: header.payload.signature.
JWT Structure: Header, Payload, Signature
Every JWT consists of three Base64URL-encoded parts joined by dots. When decoded, each part is a JSON object (except the signature, which is binary). The structure is defined in RFC 7519 and is consistent across all JWT implementations.
The three parts are independently decodable. Anyone who holds the token can read the header and payload without any key. Only the signature requires the key to verify. This is a fundamental and frequently misunderstood property: JWTs are not secret by default — they are only signed.
The Header
The header is a JSON object containing two fields:
{
"alg": "HS256",
"typ": "JWT"
}
alg specifies the algorithm used to sign the token (e.g., HS256, RS256, ES256). typ is always "JWT". The header is Base64URL-encoded to produce the first segment of the token.
The Payload and Claims
The payload contains claims — statements about the subject and other metadata. Claims fall into three categories:
Registered Claims
Defined in RFC 7519 and recognised by all JWT libraries:
iss(issuer) — who issued the tokensub(subject) — who the token is about (typically a user ID)aud(audience) — intended recipientsexp(expiration time) — Unix timestamp after which the token is invalidnbf(not before) — Unix timestamp before which the token must not be acceptediat(issued at) — Unix timestamp when the token was issuedjti(JWT ID) — unique identifier for the token (used to prevent replay attacks)
Public Claims
Custom claims defined by the application that should be registered with IANA or namespaced to avoid collisions. Examples: email, role, permissions.
Private Claims
Custom claims agreed upon by both parties. These are application-specific and not standardised.
The Signature
The signature verifies that the token was issued by a trusted party and has not been tampered with. It is computed as:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
For HMAC-based algorithms (HS256), the secret is shared between issuer and verifier. If anyone modifies the header or payload, the signature will not match and the token must be rejected.
For RSA-based algorithms (RS256), the issuer signs with a private key and verifiers use the corresponding public key. This is more appropriate for distributed systems where multiple services verify tokens but only one service issues them.
Base64URL Encoding
Standard Base64 uses characters + and /, which have special meanings in URLs. Base64URL substitutes - for + and _ for /, and omits padding characters (=). This makes JWTs safe to include in URLs and HTTP headers without additional encoding.
See our guide on Base64 encoding for a deeper explanation of the underlying encoding mechanism.
Signing Algorithms: HS256 vs RS256
| Property | HS256 | RS256 | ES256 |
|---|---|---|---|
| Type | Symmetric (shared secret) | Asymmetric (RSA key pair) | Asymmetric (ECDSA) |
| Key distribution | Secret must be shared | Public key distributed freely | Public key distributed freely |
| Best for | Single-service architectures | Multi-service / microservices | Mobile / constrained environments |
| Signature size | 32 bytes | 256–512 bytes | 64 bytes |
| Performance | Fastest | Slower (RSA operations) | Fast (elliptic curve) |
For monolithic applications or scenarios where both parties are the same service, HS256 is simple and efficient. For architectures where a separate authentication service issues tokens consumed by multiple APIs, RS256 or ES256 is preferred because resource servers can verify tokens using only the public key.
JWT vs Session Cookies
Traditional web applications store session state server-side: a session ID is stored in a cookie and the server looks up the corresponding session data (user ID, permissions) on each request. JWTs take a different approach: all the state is embedded in the token itself, making the server stateless.
Advantages of JWTs:
- Stateless — no server-side session store required, scales horizontally easily
- Cross-domain — works naturally across multiple domains and services
- Mobile-friendly — works well in native apps without cookie support
Advantages of session cookies:
- Easy revocation — delete the session record to invalidate immediately
- No payload size limit — session data stays server-side
- HttpOnly cookies provide good XSS protection
The biggest practical limitation of JWTs is revocation: once issued, a JWT is valid until it expires unless you implement a token blacklist (which reintroduces server-side state). For scenarios requiring immediate revocation (e.g., forced logout after account compromise), sessions may be more appropriate or short-lived tokens with refresh token rotation must be implemented carefully.
Security Considerations
Algorithm Confusion Attacks
A historical attack involved setting the alg field to none and removing the signature. Vulnerable libraries would accept unsigned tokens. Always explicitly specify accepted algorithms when verifying a JWT — never accept alg: none in production.
Short Expiry Times
Set the exp claim to the shortest practical value. Access tokens of 5–15 minutes, combined with refresh tokens for longer sessions, limit exposure if a token is stolen.
Secure Storage
Do not store JWTs in localStorage if the application could be vulnerable to XSS. Prefer HttpOnly cookies with Secure and SameSite=Strict attributes.
Validate All Claims
Always validate exp, iss, and aud claims. Failing to validate the audience claim can allow tokens intended for one service to be accepted by another.
Try It Free — No Signup Required
Decode any JWT token instantly and inspect its header, payload claims, and expiry — all in your browser without sending data anywhere.
Open JWT Decoder