Description
JSON Web Tokens (JWT) are widely used for authentication, but just decoding them is not enoughβyou need to verify their signature too. In this blog, weβll break down how to decode a JWT and verify its signature using JavaScript, all in simple terms.
π What is a JWT?
A JWT (JSON Web Token) is a compact, URL-safe token used for securely transmitting information. It has three parts:
HEADER.PAYLOAD.SIGNATURE
Example JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NSIsIm5hbWUiOiJKb2huIERvZSIsImV4cCI6MTcxNjAwMDAwMH0.ZXhhbXBsZXNpZ25hdHVyZQ
- Header β Metadata about the token (e.g., algorithm used: HS256)
-
Payload β Data like user ID, roles, and expiration time (
exp
) - Signature β A secret-key-based hash to verify authenticity
Without verifying the signature, anyone can modify a JWT, which is a security risk! π±
π Step 1: Decode the JWT in JavaScript
Before verifying a JWT, let's first decode it to extract the payload (the actual data inside the token).
π JavaScript Code to Decode JWT
function jwtDecode(token) {
try {
const base64Url = token.split(".")[1];
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
const jsonPayload = decodeURIComponent(
window
.atob(base64)
.split("")
.map((c) => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`)
.join("")
);
const decoded = JSON.parse(jsonPayload);
// Check if token has expired
if (decoded.exp) {
const currentTime = Math.floor(Date.now() / 1000);
if (decoded.exp < currentTime) {
console.warn("Token has expired!");
return null;
}
}
return decoded;
} catch (error) {
console.error("Invalid JWT token", error);
return null;
}
}
πΉ How It Works?
- Splits the token into three parts and extracts the payload (middle part).
- Converts Base64 URL-safe encoding into a normal Base64 string.
- Decodes it into a readable JSON object.
- Checks if the token has expired using the
exp
field.
π΄ Problem: This does not verify the signature, so anyone could tamper with the payload! π¨
π Step 2: Verify the JWT Signature
To ensure the token is authentic and not modified, we need to verify its signature using a secret key (e.g., "test"
).
β JavaScript Code to Verify JWT Signature
async function jwtVerify(token, secret = "test") {
try {
const parts = token.split(".");
if (parts.length !== 3) throw new Error("Invalid JWT format");
const [headerB64, payloadB64, signatureB64] = parts;
const header = JSON.parse(atob(headerB64));
const payload = JSON.parse(atob(payloadB64));
const currentTime = Math.floor(Date.now() / 1000);
if (payload.exp && payload.exp < currentTime) {
console.warn("Token has expired!");
return null;
}
const encoder = new TextEncoder();
const keyData = encoder.encode(secret);
const cryptoKey = await crypto.subtle.importKey("raw", keyData, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
const data = encoder.encode(`${headerB64}.${payloadB64}`);
const newSignature = await crypto.subtle.sign("HMAC", cryptoKey, data);
const newSignatureB64 = btoa(String.fromCharCode(...new Uint8Array(newSignature)))
.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
if (newSignatureB64 !== signatureB64) {
throw new Error("Invalid signature! JWT is not authentic.");
}
return payload;
} catch (error) {
console.error("JWT Verification Failed:", error.message);
return null;
}
}
πΉ How It Works?
- Splits the JWT into three parts: Header, Payload, Signature.
- Decodes Header & Payload to JSON format.
-
Checks expiration time (
exp
field). - Recreates the signature using HMAC-SHA256 and compares it with the original signature.
- β If valid, returns decoded payload. Otherwise, it rejects the token.
π¬ Example Usage
const token = "YOUR_JWT_HERE"; // Replace with an actual JWT
jwtVerify(token).then((decoded) => {
if (decoded) {
console.log("β
Valid Token:", decoded);
} else {
console.log("β Invalid or Expired Token.");
}
});
π― Summary
Step | Action | Code |
---|---|---|
1οΈβ£ | Decode JWT | Extracts and reads payload (unsafe on its own) |
2οΈβ£ | Verify Signature | Ensures token authenticity using a secret key (HMAC-SHA256) |
3οΈβ£ | Check Expiration | Rejects expired tokens (via exp field) |
πΉ Always verify the signature before trusting a JWT!
π‘ Final Thoughts
β JWTs are great for authentication, but decoding alone is not safe. Always verify the signature before accepting a token!
π Want even better security? Use jsonwebtoken in Node.js:
const jwt = require("jsonwebtoken");
jwt.verify(token, "test");
Top comments (0)