Role‐Based Access Control (RBAC) - sonuprajapati15/Authentication-Authorization GitHub Wiki
Role-Based Access Control (RBAC) is an authorization model where users are assigned roles, and roles have specific permissions to access resources. This provides structured access control and prevents unauthorized actions.
🔹 Example:
- Admin → Can create, read, update, and delete users.
- Editor → Can create and edit content but cannot delete.
- Viewer → Can only read content.
✅ Users can authenticate and receive an access token.
✅ Users have roles (Admin, Editor, Viewer, etc.).
✅ Roles have permissions (create, read, update, delete).
✅ API endpoints enforce role-based access control.
✅ Admins can manage roles and permissions dynamically.
⚡ Security – Prevent unauthorized access using proper role validation.
⚡ Scalability – Support thousands of users with efficient role checks.
⚡ Performance – Optimize role validation with caching (e.g., Redis).
⚡ Compliance – Ensure GDPR, HIPAA compliance for sensitive data.
⚡ Flexibility – Allow easy addition of new roles and permissions.
- User Management Service – Handles authentication & role assignment.
- RBAC Middleware – Validates roles & permissions before granting access.
- Resource Server – Hosts protected endpoints that require role-based access.
- Database – Stores user roles, permissions, and assignments.
- Caching Layer (Redis) – Caches role-permission mappings for performance.
- User logs in – Receives a JWT token with role information.
-
Client sends request – Includes JWT in headers (
Authorization: Bearer <token>
). - RBAC Middleware validates role – Checks if the role has required permissions.
- Access granted or denied – If permitted, request proceeds; otherwise, access is denied.
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(255) UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
role_id INT REFERENCES roles(id)
);
CREATE TABLE roles (
id SERIAL PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL
);
CREATE TABLE permissions (
id SERIAL PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL
);
CREATE TABLE role_permissions (
role_id INT REFERENCES roles(id) ON DELETE CASCADE,
permission_id INT REFERENCES permissions(id) ON DELETE CASCADE,
PRIMARY KEY (role_id, permission_id)
);
Method | Endpoint | Description |
---|---|---|
POST | /login | Authenticate user and return JWT token |
GET | /users | (Admin) List all users |
POST | /roles | (Admin) Create a new role |
POST | /permissions | (Admin) Define new permissions |
POST | /assign-role | Assign role to a user |
GET | /dashboard | (Editor, Admin) Access dashboard |
GET | /reports | (Viewer, Admin) View reports |
Here is the RBAC Authorization Flowchart:
View or edit this diagram in Whimsical.
npm install express bcrypt jsonwebtoken redis dotenv
require("dotenv").config();
const express = require("express");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const redis = require("redis");
const app = express();
app.use(express.json());
const redisClient = redis.createClient({ url: process.env.REDIS_URL });
// Mock database
const users = [
{ id: 1, username: "admin", passwordHash: bcrypt.hashSync("password", 10), role: "admin" },
{ id: 2, username: "editor", passwordHash: bcrypt.hashSync("password", 10), role: "editor" },
{ id: 3, username: "viewer", passwordHash: bcrypt.hashSync("password", 10), role: "viewer" }
];
const permissions = {
admin: ["manage_users", "create_content", "view_reports"],
editor: ["create_content", "edit_content"],
viewer: ["view_reports"]
};
// RBAC Middleware
const authorize = (requiredPermission) => (req, res, next) => {
const token = req.headers.authorization?.split(" ")[1];
if (!token) return res.status(401).json({ message: "Unauthorized" });
try {
const { role } = jwt.verify(token, process.env.JWT_SECRET);
if (!permissions[role]?.includes(requiredPermission)) {
return res.status(403).json({ message: "Access Denied" });
}
next();
} catch {
return res.status(401).json({ message: "Invalid Token" });
}
};
// Login Route
app.post("/login", async (req, res) => {
const { username, password } = req.body;
const user = users.find((u) => u.username === username);
if (!user || !(await bcrypt.compare(password, user.passwordHash))) {
return res.status(401).json({ message: "Invalid credentials" });
}
const token = jwt.sign({ role: user.role }, process.env.JWT_SECRET);
res.json({ message: "Login successful", token });
});
// Protected Routes
app.get("/users", authorize("manage_users"), (req, res) => res.json({ message: "User Management" }));
app.get("/dashboard", authorize("create_content"), (req, res) => res.json({ message: "Dashboard Access" }));
app.get("/reports", authorize("view_reports"), (req, res) => res.json({ message: "Report Viewing" }));
app.listen(3000, () => console.log("RBAC Server running on port 3000"));
- Admin → Can manage users, roles, permissions.
- Editor → Can manage content but not users.
- Viewer → Can only read content.
- Redis stores role-permission mappings for fast lookup.
- Cache invalidation occurs when a role or permission changes.
Factor | Trade-off |
---|---|
Security | RBAC is strong, but requires careful role management. |
Performance | Using caching (e.g., Redis) reduces DB queries for role validation. |
Flexibility | Adding new roles & permissions is easy but requires schema updates. |
Scalability | Works well for large-scale systems but may need distributed caching in microservices. |
RBAC enhances security by ensuring users can only access what they are authorized for. It is efficient, scalable, and widely used in enterprise applications.