JWT Authentication — Complete Implementation
Advertisement
JWT (JSON Web Tokens) are standard for stateless authentication. Perfect for APIs and distributed systems.
JWT Basics
A JWT has three parts: header.payload.signature
import jwt from "jsonwebtoken";
const secret = process.env.JWT_SECRET || "your-secret";
// Generate token
const token = jwt.sign(
{ userId: 123, email: "user@example.com" },
secret,
{ expiresIn: "24h" }
);
// Verify token
const decoded = jwt.verify(token, secret);
console.log(decoded); // { userId: 123, email: '...', iat, exp }
Complete Authentication Flow
// Register
app.post("/register", async (req, res) => {
const { email, password } = req.body;
const hashed = await bcrypt.hash(password, 10);
const user = await db.users.create({ email, password: hashed });
const token = jwt.sign({ userId: user.id }, secret, { expiresIn: "24h" });
res.json({ token });
});
// Login
app.post("/login", async (req, res) => {
const { email, password } = req.body;
const user = await db.users.findOne({ email });
if (!user || !(await bcrypt.compare(password, user.password))) {
return res.status(401).json({ error: "Invalid credentials" });
}
const token = jwt.sign({ userId: user.id }, secret, { expiresIn: "24h" });
res.json({ token });
});
// Protected route
app.get("/me", authMiddleware, (req: any, res) => {
res.json({ userId: req.userId });
});
// Middleware
const authMiddleware = (req: any, res: any, next: any) => {
const token = req.headers.authorization?.split(" ")[1];
if (!token) return res.status(401).json({ error: "No token" });
try {
const decoded = jwt.verify(token, secret) as any;
req.userId = decoded.userId;
next();
} catch {
res.status(401).json({ error: "Invalid token" });
}
};
Refresh Tokens
// Generate tokens
function generateTokens(userId: number) {
const accessToken = jwt.sign({ userId }, secret, { expiresIn: "15m" });
const refreshToken = jwt.sign({ userId }, refreshSecret, { expiresIn: "7d" });
return { accessToken, refreshToken };
}
// Refresh endpoint
app.post("/refresh", (req, res) => {
const { refreshToken } = req.body;
try {
const decoded = jwt.verify(refreshToken, refreshSecret) as any;
const tokens = generateTokens(decoded.userId);
res.json(tokens);
} catch {
res.status(401).json({ error: "Invalid refresh token" });
}
});
Best Practices
const config = {
// Use strong secret
secret: process.env.JWT_SECRET,
// Short expiration for security
accessTokenExpiry: "15m",
// Longer for refresh token
refreshTokenExpiry: "7d",
// Sign with algorithm
algorithm: "HS256" as const,
};
// Token payload (minimize data)
interface TokenPayload {
userId: number;
email?: string; // Optional, avoid large payloads
}
// Store refresh tokens in database
app.post("/logout", authMiddleware, async (req: any, res) => {
await db.refreshTokens.delete(req.userId);
res.json({ ok: true });
});
Securing JWTs
- HTTPS only - tokens in transport must be encrypted
- httpOnly cookies - store in httpOnly cookies, not localStorage
- CORS properly - restrict cross-origin requests
- Short expiration - access tokens 15-60 minutes
- Revocation - implement token blacklist for logout
// Store in httpOnly cookie
app.post("/login", async (req, res) => {
const { token } = generateTokens(user.id);
res.cookie("token", token, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
maxAge: 15 * 60 * 1000, // 15 minutes
});
res.json({ ok: true });
});
// Read from cookie
app.use((req: any, res, next) => {
const token = req.cookies.token || req.headers.authorization?.split(" ")[1];
if (token) {
try {
req.user = jwt.verify(token, secret);
} catch {}
}
next();
});
FAQ
Q: Should I store user data in JWT? A: Minimize data. Only store userId. Fetch other data from database.
Q: What if I need to update user permissions? A: Use short-lived tokens. Re-authenticate on permission changes.
Q: How do I handle token expiration gracefully? A: Use refresh tokens. Access token expires, use refresh to get new access token.
JWT is the standard for modern API authentication. Implement it correctly and you have a secure, scalable system.
Advertisement