Password Hashing with Bcrypt & Role-Based Access Control (RBAC)0%

Password Hashing with Bcrypt & Role-Based Access Control (RBAC)

Beginner12 min read•Updated: Jul 11, 2026
Study MaterialsCheatsheet

Password Hashing with Bcrypt & Role-Based Access Control (RBAC)

Storing plaintext passwords in a database is an egregious security violation. In this tutorial, we implement military-grade password hashing with Bcrypt and implement Role-Based Access Control (RBAC) to restrict sensitive endpoints based on user permissions.


1. Why Bcrypt? (Salting & Adaptive Work Factors)

MD5 and SHA-256 are designed to be fast, making them vulnerable to modern GPU brute-force attacks capable of testing billions of hashes per second.

Bcrypt counters this with two essential security features:

  1. 1
    Cryptographic Salt: Appends random bytes to the password before hashing, preventing Rainbow Table lookup attacks.
  2. 2
    Adaptive Work Factor (Cost Factor): Allows developers to slow down the algorithm exponentially. A cost factor of 12 means an attacker takes hundreds of milliseconds per guess on high-end hardware, making brute force economically impossible.
JavaScript
import bcrypt from 'bcrypt';
 
const SALT_ROUNDS = 12;
 
// Hash password before saving to database
export async function hashPassword(plainPassword) {
return await bcrypt.hash(plainPassword, SALT_ROUNDS);
}
 
// Compare password during login
export async function verifyPassword(plainPassword, storedHash) {
return await bcrypt.compare(plainPassword, storedHash);
}

2. Role-Based Access Control (RBAC) Architecture

RBAC restricts resource access based on assigned organizational roles (e.g., student, instructor, admin, superadmin).

Output
Incoming Request -> [ Authenticate JWT ] -> [ RestrictTo('admin', 'instructor') ] -> [ Controller ]

Implementing the Authorization Guard:

JavaScript
// src/middleware/authorize.js
export const restrictTo = (...allowedRoles) => {
return (req, res, next) => {
// req.user was populated by prior authentication middleware
if (!req.user || !allowedRoles.includes(req.user.role)) {
return res.status(403).json({
status: 'fail',
message: `Forbidden: You do not have permission to perform this action. Required: [${allowedRoles.join(', ')}]`
});
}
next();
};
};

3. Protecting Admin Endpoints

JavaScript
import { Router } from 'express';
import { protectRoute } from '../middleware/auth.middleware.js';
import { restrictTo } from '../middleware/authorize.js';
import * as userController from '../controllers/user.controller.js';
 
const router = Router();
 
// 1. Any logged-in user can view their own profile
router.get('/me', protectRoute, userController.getMyProfile);
 
// 2. ONLY users with role 'admin' can delete other user accounts
router.delete('/:id', protectRoute, restrictTo('admin'), userController.deleteUser);
 
// 3. Instructors or Admins can publish courses
router.post('/courses', protectRoute, restrictTo('instructor', 'admin'), userController.createCourse);
 
export default router;

Interactive Quiz

Multiple Choice Questions

Question 1
Why are fast hashing algorithms like SHA-256 unsuitable for storing user passwords compared to Bcrypt?
Question 2
What is a "Salt" in password hashing?
Question 3
What does bcrypt.compare(candidatePassword, userHash) return?
Question 4
In Role-Based Access Control (RBAC), what HTTP status code indicates that the authenticated user lacks sufficient permissions for a requested resource?
Question 5
What is the recommended default salt work factor (cost) for Bcrypt in modern web applications?

Next Lesson

Security Hardening: Helmet, CORS, Express Rate Limiting & HPP

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext