Kritim Yantra
Aug 08, 2025
Ever built a Next.js app, only to realize you have no idea how to handle authentication securely? 😅 You're not alone!
I remember my first time trying to implement user roles—"Should I store permissions in localStorage? How do I protect admin routes?"—it was a mess. I ended up with spaghetti code, security holes, and a lot of frustration.
But here’s the good news: JWT (JSON Web Tokens) + role-based access control doesn’t have to be complicated. In this guide, I’ll walk you through a simple, secure, and scalable authentication system for Next.js using JWT, roles, and permissions—without overcomplicating things.
Let’s dive in!
✅ JWT Authentication – Secure user login & token management
✅ Role-Based Access Control (RBAC) – Define user roles (e.g., Admin, User, Guest)
✅ Permission Checks – Restrict access to pages & API routes
✅ Protecting Routes – Server-side & client-side guards
By the end, you’ll have a production-ready auth system. 🚀
We’ll use:
jsonwebtoken
(JWT generation & verification) bcryptjs
(password hashing) next-iron-session
(secure session management)npm install jsonwebtoken bcryptjs next-iron-session
// pages/api/login.js
import jwt from 'jsonwebtoken';
import bcrypt from 'bcryptjs';
export default async function handler(req, res) {
if (req.method !== 'POST') return res.status(405).end();
const { email, password } = req.body;
// 1. Find user in DB (mock example)
const user = { id: 1, email: 'user@example.com', password: '$2a$10$hashedPassword', role: 'user' };
// 2. Verify password
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) return res.status(401).json({ error: 'Invalid credentials' });
// 3. Generate JWT
const token = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
);
res.status(200).json({ token });
}
// pages/api/login.js (updated)
res.setHeader('Set-Cookie', `token=${token}; HttpOnly; Secure; Path=/; SameSite=Strict`);
res.status(200).json({ success: true });
// After successful login (client-side)
localStorage.setItem('token', token);
const ROLES = {
ADMIN: 'admin',
USER: 'user',
GUEST: 'guest',
};
// pages/api/admin-route.js
import jwt from 'jsonwebtoken';
export default function handler(req, res) {
const token = req.cookies.token || req.headers.authorization?.split(' ')[1];
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// Check if user is admin
if (decoded.role !== ROLES.ADMIN) {
return res.status(403).json({ error: 'Forbidden' });
}
// Proceed if authorized
res.status(200).json({ secretAdminData: "You're in!" });
} catch (err) {
res.status(401).json({ error: 'Unauthorized' });
}
}
useEffect
Check)// hooks/useAuth.js
import { useEffect } from 'react';
import { useRouter } from 'next/router';
export function useAuth(requiredRole) {
const router = useRouter();
useEffect(() => {
const token = localStorage.getItem('token');
if (!token) router.push('/login');
const decoded = jwt.decode(token);
if (decoded.role !== requiredRole) router.push('/unauthorized');
}, []);
}
// pages/admin/dashboard.js
import { useAuth } from '../../hooks/useAuth';
export default function AdminDashboard() {
useAuth('admin'); // Redirects if not admin
return <div>Welcome, Admin!</div>;
}
For fine-grained control:
// utils/permissions.js
const PERMISSIONS = {
DELETE_POST: 'delete_post',
EDIT_USER: 'edit_user',
};
export function hasPermission(user, permission) {
return user.permissions?.includes(permission);
}
✔ Never store JWT in localStorage if you can avoid it (use HTTP-only cookies).
✔ Always validate tokens server-side (don’t trust client-side checks).
✔ Use short-lived tokens (e.g., 1h expiry) + refresh tokens for better security.
Q: Should I use Next.js API routes or an external auth service like Auth0?
A: For small apps, Next.js API is fine. For production, consider Auth0/Firebase for scalability.
Q: How do I handle token expiration?
A: Implement a refresh token system or redirect to login when expired.
Q: Is JWT secure enough?
A: Yes, if used correctly (secure storage, short expiry, proper validation).
What’s your biggest struggle with Next.js auth? JWT confusion? Role management? Let me know in the comments! 👇
Happy coding! 🚀🔥
No comments yet. Be the first to comment!
Please log in to post a comment:
Sign in with Google