How to Decode a JWT in JavaScript and React (No Library)
- A reusable decodeJwt() function using only built-in browser APIs
- How to use it in React to read user claims from an access token
- Reading exp to check expiry before making API calls
- Why you should never use decoded claims for client-side authorization
Table of Contents
You can decode a JWT in JavaScript in three lines using only built-in browser APIs — no jsonwebtoken, no jwt-decode package, no npm install. Here is the function and how to use it in React.
Decode JWT in JavaScript — Pure Browser APIs
function decodeJwt(token) {
const parts = token.split('.');
if (parts.length !== 3) throw new Error('Invalid JWT format');
const payload = parts[1];
// atob decodes base64; replace handles base64url chars
const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));
return JSON.parse(decoded);
}
// Usage
const payload = decodeJwt(token);
console.log(payload.sub); // user ID
console.log(payload.email); // email if present
console.log(payload.exp); // expiry timestamp
This uses atob(), available in all modern browsers and Node.js 16+. The replace calls convert base64url encoding to standard base64 before decoding.
Note: some tokens have payload segments whose length causes atob to fail without padding. A safer version:
function decodeJwt(token) {
const payload = token.split('.')[1];
const padded = payload + '=='.slice(0, (4 - payload.length % 4) % 4);
return JSON.parse(atob(padded.replace(/-/g, '+').replace(/_/g, '/')));
}
Using decodeJwt in React Components
A common pattern is to read user info from an access token stored in memory or a cookie:
import { useState, useEffect } from 'react';
function useCurrentUser(token) {
const [user, setUser] = useState(null);
useEffect(() => {
if (!token) return;
try {
const payload = decodeJwt(token);
setUser({
id: payload.sub,
email: payload.email,
name: payload.name,
expiresAt: payload.exp * 1000 // convert to ms
});
} catch (e) {
setUser(null);
}
}, [token]);
return user;
}
// In your component
const user = useCurrentUser(accessToken);
if (user) return <p>Hello {user.name}</p>;
The exp * 1000 conversion is important — JWT timestamps are seconds since epoch, but JavaScript's Date uses milliseconds.
Check If a JWT Is Expired in JavaScript
function isJwtExpired(token) {
try {
const { exp } = decodeJwt(token);
if (!exp) return false; // no expiry = does not expire
return Date.now() / 1000 > exp;
} catch {
return true; // malformed token treated as expired
}
}
// Before making an API call
if (isJwtExpired(accessToken)) {
await refreshToken();
}
This is a client-side convenience check only. Your server must always validate the token independently — a malicious user can forge a client-side expiry check by replacing the token in memory.
Should You Use jwt-decode npm Package?
The jwt-decode npm package does the same thing as the function above — it is around 1KB and handles edge cases. There is no strong reason to install it for most projects since the vanilla implementation is short and easy to understand.
Use the npm package if:
- Your project already has it as a dependency
- You want TypeScript types out of the box
Use the vanilla function if:
- You want to avoid adding a dependency for a 5-line utility
- You are building a library that should have minimal dependencies
Either way, remember: client-side decoding is for reading claims only. Signature verification always belongs on the server.
Test Your Decoder Logic — Try the Browser Tool
Paste your JWT above to verify what the payload contains before writing your decoding logic.
Open Free JWT DecoderFrequently Asked Questions
Does atob work in Node.js?
atob is available globally in Node.js 16 and later. In older Node.js versions, use Buffer.from(payload, "base64").toString("utf-8") instead of atob(payload).
Can I use this to validate the JWT signature?
No. This only decodes the payload — it does not verify the signature. Anyone can modify a JWT payload if the signature is not verified. Never trust decoded claims for security decisions without server-side validation.
What does "Invalid JWT format" mean?
The token must have exactly two dots separating three base64url segments. If you see this error, check that you have the full token and have not accidentally truncated it or included extra whitespace.
How do I decode a JWT in Angular?
The same decodeJwt() function works in Angular. You can create it as an injectable service or a standalone utility function. Angular does not provide a built-in JWT decoder.

