Role-Based Access Control (RBAC) in the MERN Stack
Role-Based Access Control ensures that only authorized users can access specific routes, components, or actions based on their role (e.g., Admin, User, Editor).
Common roles:
Admin – full access
Editor – can modify some content
User – basic access
Guest – very limited access
RBAC improves security, prevents unauthorized access, and keeps your app scalable.
1. Designing Roles in MongoDB
A typical user document in MongoDB might look like:
{
"_id": "12345",
"name": "Alice",
"email": "alice@example.com",
"password": "...hashed...",
"role": "admin" // or "user" or "editor"
}
You can store:
a single role ("admin")
multiple roles (["editor", "reviewer"])
role + permissions model (advanced)
2. Adding Role Field in User Schema (Mongoose)
// models/User.js
import mongoose from "mongoose";
const userSchema = new mongoose.Schema({
name: String,
email: { type: String, unique: true },
password: String,
role: {
type: String,
enum: ["user", "editor", "admin"],
default: "user"
}
});
export default mongoose.model("User", userSchema);
3. Assigning Roles on Signup / Admin Panel
Example signup route:
// default role = "user"
const newUser = await User.create({
name,
email,
password: hashedPassword,
role: "user"
});
Admins can later update roles:
await User.findByIdAndUpdate(id, { role: "editor" });
4. Generating JWT with Role
When the user logs in, include the role in the JWT payload:
import jwt from "jsonwebtoken";
const token = jwt.sign(
{
id: user._id,
role: user.role
},
process.env.JWT_SECRET,
{ expiresIn: "1d" }
);
This allows the backend to check roles on each request.
5. Middleware: Protect Routes + Check Roles
A. Authentication Middleware
Verify token and attach user info to req.user.
// middleware/auth.js
import jwt from "jsonwebtoken";
export const auth = (req, res, next) => {
const token = req.headers.authorization?.split(" ")[1];
if (!token) return res.status(401).json({ message: "Unauthorized" });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded; // contains id + role
next();
} catch (error) {
res.status(401).json({ message: "Invalid token" });
}
};
B. Role Authorization Middleware
// middleware/authorize.js
export const authorize = (...allowedRoles) => {
return (req, res, next) => {
if (!allowedRoles.includes(req.user.role)) {
return res.status(403).json({ message: "Forbidden: Access denied" });
}
next();
};
};
Usage:
router.post("/admin-only", auth, authorize("admin"), handler);
router.put("/edit-post", auth, authorize("editor", "admin"), handler);
6. Protecting Backend Routes
Example:
import express from "express";
import { auth } from "../middleware/auth.js";
import { authorize } from "../middleware/authorize.js";
const router = express.Router();
router.get("/users", auth, authorize("admin"), async (req, res) => {
const users = await User.find();
res.json(users);
});
export default router;
Only admin can access /users.
7. Frontend (React) Role Handling
Store role after login, typically in:
React Context
Redux store
localStorage (short-term; avoid storing sensitive data)
Example:
localStorage.setItem("role", user.role);
Protecting React Routes
Route Wrapper
// components/ProtectedRoute.jsx
import { Navigate } from "react-router-dom";
export default function ProtectedRoute({ children, role, allowedRoles }) {
if (!role) return <Navigate to="/login" />;
if (!allowedRoles.includes(role)) return <Navigate to="/not-authorized" />;
return children;
}
Usage:
<ProtectedRoute role={role} allowedRoles={["admin"]}>
<AdminDashboard />
</ProtectedRoute>
8. Showing/Hiding UI Elements Based on Role
{role === "admin" && (
<button onClick={deleteUser}>Delete User</button>
)}
or more complex:
const allowed = ["editor", "admin"].includes(role);
9. Best Practices for RBAC in MERN
Security
✔ Never trust frontend-only role checking
✔ Always verify role again on the backend
✔ Avoid storing JWTs in localStorage if possible (use httpOnly cookies)
Scalability
✔ Use role + permission system for large apps
✔ Keep roles in config files, not hardcoded everywhere
✔ Add logging for unauthorized access attempts
Maintainability
✔ Centralize RBAC logic in middleware
✔ Keep user roles consistent (ENUM or separate Role table)
10. Example Folder Structure
backend/
models/
routes/
middleware/
auth.js
authorize.js
controllers/
app.js
frontend/
src/
components/
pages/
context/
utils/
Summary
To implement RBAC in a MERN app:
Store roles in MongoDB (User model).
Include role in JWT during login.
Use auth middleware for authentication.
Use authorize middleware to restrict routes.
Protect React routes and hide UI based on roles.
Secure backend as the ultimate authority.
This makes your MERN app secure, scalable, and easy to manage.
Learn MERN Stack Training in Hyderabad
Read More
Visit Our Quality Thought Training Institute in Hyderabad
Subscribe by Email
Follow Updates Articles from This Blog via Email
No Comments