In modern applications, security is paramount. Role-Based Access Control (RBAC) is a powerful way to manage access to resources by assigning roles to users. Coupled with JSON Web Token (JWT) authentication, RBAC becomes a seamless and secure method for protecting routes in your Node.js application.
1. What is Role-Based Access Control?
Role-Based Access Control (RBAC) restricts access based on users’ roles. For example:
- Admin: Can manage all resources.
- Editor: Can modify content but not delete it.
- Viewer: Can only view content.
RBAC ensures users can only perform actions permitted for their role, reducing security vulnerabilities.
2. Why Use JWT for Authentication?
JWT (JSON Web Token) is a compact, URL-safe token for securely transmitting information between parties. JWT is widely used for its simplicity and stateless nature. It encodes user data and serves as a mechanism for authorization and authentication.
3. Setting Up the Node.js Application
Start by setting up a basic Node.js application with express
for handling routes and jsonwebtoken
for JWT.
Step 1: Initialize the Project
mkdir rbac-nodejs
cd rbac-nodejs
npm init -y
npm install express jsonwebtoken bcryptjs body-parser dotenv
Step 2: Create Basic Structure
Your folder structure should look like this:
rbac-nodejs/
│
├── .env
├── server.js
├── routes/
│ ├── auth.js
│ └── user.js
└── middleware/
├── authenticate.js
└── authorize.js
Step 3: Configure server.js
Create a simple server setup:
require("dotenv").config();
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.use(bodyParser.json());
// Routes
app.use("/auth", require("./routes/auth"));
app.use("/user", require("./routes/user"));
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
4. Implementing JWT Authentication
JWT consists of three parts: Header, Payload, and Signature. Let’s implement login and token generation.
Create the auth.js Route
const express = require("express");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcryptjs");
const router = express.Router();
const users = [
{
id: 1,
username: "admin",
password: bcrypt.hashSync("admin123", 10),
role: "admin",
},
{
id: 2,
username: "editor",
password: bcrypt.hashSync("editor123", 10),
role: "editor",
},
];
// Login Endpoint
router.post("/login", (req, res) => {
const { username, password } = req.body;
const user = users.find((u) => u.username === username);
if (!user || !bcrypt.compareSync(password, user.password)) {
return res.status(401).json({ message: "Invalid credentials" });
}
const token = jwt.sign({ id: user.id, role: user.role }, process.env.JWT_SECRET, { expiresIn: "1h" });
res.json({ token });
});
module.exports = router;
5. Adding RBAC to Your Application
Middleware for Authentication
Create authenticate.js
to verify the JWT.
const jwt = require("jsonwebtoken");
function authenticate(req, res, next) {
const token = req.headers["authorization"];
if (!token) return res.status(403).json({ message: "No token provided" });
jwt.verify(token.split(" ")[1], process.env.JWT_SECRET, (err, decoded) => {
if (err) return res.status(401).json({ message: "Unauthorized" });
req.user = decoded;
next();
});
}
module.exports = authenticate;
Middleware for Authorization
Create authorize.js
to restrict access based on roles.
function authorize(roles) {
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return res.status(403).json({ message: "Access forbidden" });
}
next();
};
}
module.exports = authorize;
6. Protecting Routes
Create the user.js Route
Add endpoints that use RBAC for access control.
const express = require("express");
const authenticate = require("../middleware/authenticate");
const authorize = require("../middleware/authorize");
const router = express.Router();
// Open to all authenticated users
router.get("/profile", authenticate, (req, res) => {
res.json({ message: `Welcome, user ${req.user.id}!`, role: req.user.role });
});
// Admin-only route
router.delete("/delete", authenticate, authorize(["admin"]), (req, res) => {
res.json({ message: "User deleted successfully!" });
});
// Editor and Admin route
router.post("/edit", authenticate, authorize(["editor", "admin"]), (req, res) => {
res.json({ message: "Content edited successfully!" });
});
module.exports = router;
7. Testing and Securing the App
- Generate a Token: Use the
/auth/login
endpoint to obtain a JWT by providing valid credentials. - Test Routes: Use a tool like Postman to access the endpoints with and without the token.
- Secure Your App:
- Use HTTPS in production.
- Store JWT secrets securely using
dotenv
or a similar tool. - Implement token blacklisting if necessary.
8. Conclusion
RBAC and JWT together provide a scalable and secure way to manage access in Node.js applications. With this setup, you can dynamically manage user roles and permissions, ensuring secure access to your application resources.
You may also like:
1) How do you optimize a website’s performance?
2) Change Your Programming Habits Before 2025: My Journey with 10 CHALLENGES
3) Senior-Level JavaScript Promise Interview Question
4) What is Database Indexing, and Why is It Important?
5) Can AI Transform the Trading Landscape?
Read more blogs from Here
Share your experiences in the comments, and let’s discuss how to tackle them!
Follow me on Linkedin
Trust me, I’m a software developer—debugging by day, chilling by night.