JSON Web Tokens (JWT) are commonly used to authenticate users and pass claims securely between clients and servers. Understanding how they are structured and stored is essential to build secure web applications and prevent layout compromises.
1. JWT Structure
A JWT is a string composed of three parts separated by dots (HEADER.PAYLOAD.SIGNATURE):
- Header: Specifies the algorithm (e.g. HS256) and token type (JWT).
- Payload: Contains the user claims, role IDs, and expiration times.
- Signature: Used to verify that the token has not been altered.
HEADER.PAYLOAD.SIGNATURE
2. Client-Side JWT Decoding
You can decode a JWT payload client-side to read claim values (such as names or permissions) using standard JavaScript:
function decodeJwtPayload(token) {
const parts = token.split('.');
if (parts.length !== 3) throw new Error('Invalid token structure');
const base64Url = parts[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(atob(base64).split('').map((c) => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
}
3. Secure Token Storage (LocalStorage vs HTTP-Only Cookies)
To protect tokens from Cross-Site Scripting (XSS) attacks, store them in secure, HTTP-only cookies instead of localStorage:
- localStorage: Vulnerable to XSS. If a malicious script runs on your page, it can access and steal your tokens.
- HTTP-only Cookies: Protected from XSS. The browser sends the cookie automatically with API requests, but JavaScript cannot read it directly, protecting your session data.JSON Web Tokens (JWT) are commonly used to authenticate users and pass claims securely between clients and servers. Understanding how they are structured and stored is essential to build secure web applications and prevent layout compromises.
1. JWT Structure
A JWT is a string composed of three parts separated by dots (HEADER.PAYLOAD.SIGNATURE):
- Header: Specifies the algorithm (e.g. HS256) and token type (JWT).
- Payload: Contains the user claims, role IDs, and expiration times.
- Signature: Used to verify that the token has not been altered.
HEADER.PAYLOAD.SIGNATURE
2. Client-Side JWT Decoding
You can decode a JWT payload client-side to read claim values (such as names or permissions) using standard JavaScript:
function decodeJwtPayload(token) {
const parts = token.split('.');
if (parts.length !== 3) throw new Error('Invalid token structure');
const base64Url = parts[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(atob(base64).split('').map((c) => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
}
3. Secure Token Storage (LocalStorage vs HTTP-Only Cookies)
To protect tokens from Cross-Site Scripting (XSS) attacks, store them in secure, HTTP-only cookies instead of localStorage:
- localStorage: Vulnerable to XSS. If a malicious script runs on your page, it can access and steal your tokens.
- HTTP-only Cookies: Protected from XSS. The browser sends the cookie automatically with API requests, but JavaScript cannot read it directly, protecting your session data.