What is a JSON Web Token (JWT) and How Does It Work?
A JSON Web Token (JWT), defined in RFC 7519, is an open industry standard for securely transmitting information between two parties as a compact, self-contained JSON object. Because JWTs are digitally signed using either a symmetric secret key (such as the HMAC SHA-256 algorithm) or an asymmetric public/private key pair (such as RSA or ECDSA), the authenticity and integrity of the contained data can be cryptographically verified.
JWTs are most commonly utilized in modern web architecture for stateless user authentication and authorization. When a user logs in to a web application or REST API, the authentication server signs and issues a JWT containing the user's identity claims (like user ID, email, and permission roles). The client stores this token (typically in an HTTP-only cookie or memory) and sends it within the Authorization: Bearer <token> HTTP request header on subsequent requests.
Anatomy of a JSON Web Token: The Three Segments
A serialized JWT consists of three separate strings separated by periods (.):
<Header>.<Payload>.<Signature>
1. The Header
Specifies the cryptographic signing algorithm being used (such as HS256, RS256, or ES256) and the type of token (typically "typ": "JWT"). It is encoded using Base64URL.
2. The Payload
Contains the claimsโstatements about an entity (typically the authenticated user) and any additional session metadata. This segment is also encoded using Base64URL.
3. The Signature
Generated by taking the encoded header, encoded payload, a secret or private key, and passing them through the algorithm specified in the header to ensure message integrity.
Standard Registered JWT Claims (RFC 7519 Reference)
While a JWT payload can store custom key-value pairs (such as user permissions or email addresses), the IETF specification reserves a set of standardized claims:
| Claim Key | Claim Name | Format / Type | Description |
|---|---|---|---|
| iss | Issuer | String or URI | Identifies the principal/server that issued the JWT (e.g. auth.example.com). |
| sub | Subject | String | Identifies the entity that the token represents (e.g. user ID usr_9843201). |
| aud | Audience | String or Array | Identifies the intended recipients or backend microservices that should accept the token. |
| exp | Expiration Time | NumericDate (Unix Epoch seconds) | The exact timestamp after which the token must be rejected by backend resource servers. |
| nbf | Not Before | NumericDate (Unix Epoch seconds) | Identifies the time before which the JWT must not be accepted for processing. |
| iat | Issued At | NumericDate (Unix Epoch seconds) | The exact timestamp when the token was created and signed. |
| jti | JWT ID | String (UUID) | A unique token identifier, frequently used to prevent replay attacks and facilitate token blacklisting. |
Critical Security Best Practices for JWT Implementations
- Always Enforce the Expected Algorithm on the Backend: Never blindly trust the
"alg"header provided by the incoming client token. Attackers have historically exploited weak implementations by modifying the algorithm header to"none"or converting asymmetricRS256public keys to symmetricHS256secrets. - Keep Access Token Lifetimes Short: Access tokens should have a short lifespan (typically 5 to 15 minutes). Couple access tokens with a secure, server-managed Refresh Token Rotation pattern to limit the window of vulnerability if a token is intercepted.
- Store Tokens in Secure HTTP-Only Cookies: Storing authentication JWTs in browser
localStorageorsessionStorageleaves them vulnerable to Cross-Site Scripting (XSS) attacks. Storing tokens inSameSite=Strict; Secure; HttpOnlycookies prevents client JavaScript from accessing raw tokens. - Do Not Store Sensitive Secrets in the Payload: Remember that JWT payloads are merely Base64URL-encoded, not encrypted. Passwords, API secrets, credit card numbers, or personally identifiable information (PII) should never be placed in unencrypted JWT claims.
How to Verify JWTs in Backend Code (Code Snippets)
Node.js / TypeScript (jsonwebtoken)
import jwt from 'jsonwebtoken';
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256'],
issuer: 'auth.example.com'
});
console.log('Valid token payload:', decoded);
} catch (err) {
console.error('Invalid token:', err.message);
} Python (PyJWT)
import jwt
import os
try:
payload = jwt.decode(
token,
os.environ['JWT_SECRET'],
algorithms=['HS256'],
issuer='auth.example.com'
)
print("Token valid:", payload)
except jwt.ExpiredSignatureError:
print("Token has expired")
except jwt.InvalidTokenError:
print("Invalid token signature") Frequently Asked Questions (FAQ)
Is it safe to paste confidential production JWT tokens into this debugger?
Yes, 100% safe. All Base64URL parsing, string splitting, and timestamp conversions occur strictly inside your browser's local JavaScript environment. Zero telemetry or token strings are sent to our backend servers.
What is the difference between decoding a JWT and verifying a JWT?
Decoding is the process of reversing the Base64URL encoding so that the JSON claims can be viewed by humans. Verifying requires the cryptographic private key or HMAC secret to mathematically validate that the signature matches and that the claims have not been forged.
Can a JWT be invalidated or revoked before its expiration time?
Because standard JWTs are stateless, once signed and distributed, they remain mathematically valid until their exp timestamp passes. To support immediate revocation (e.g. on user password reset), architectures typically maintain an in-memory blocklist (such as Redis) of revoked jti identifiers or increment a user-level token version number.