Role-Based Authentication in Node.js with Express.js and MongoDB

Introduction Role-Based Authentication (RBA) is a method to control access based on user roles (e.g., Admin, User, Manager). This tutorial will guide you through implementing RBA in a Node.js application using Express.js and MongoDB. Prerequisites Before we start, ensure you have the following: Node.js installed on your system MongoDB set up and running Basic knowledge of Express.js and JWT (JSON Web Tokens) A tool like Postman or cURL for API testing Steps to Implement Role-Based Authentication 1. Initialize the Project First, create a new project folder and initialize a Node.js project. mkdir role-based-auth cd role-based-auth npm init -y This creates a package.json file for managing dependencies. Now, install the required packages: npm install express mongoose bcryptjs jsonwebtoken dotenv cors express-rate-limit https express: Web framework for Node.js mongoose: ODM (Object Data Modeling) library for MongoDB bcryptjs: For hashing passwords securely jsonwebtoken: To generate and verify authentication tokens dotenv: For managing environment variables cors: To enable Cross-Origin Resource Sharing express-rate-limit: To prevent API abuse https: For secure HTTPS implementation 2. Set Up the Server Create server.js and configure the Express server: require('dotenv').config(); const express = require('express'); const mongoose = require('mongoose'); const fs = require('fs'); const https = require('https'); const rateLimit = require('express-rate-limit'); const authRoutes = require('./routes/authRoutes'); const protectedRoutes = require('./routes/protectedRoutes'); const app = express(); app.use(express.json()); app.use('/api/auth', authRoutes); app.use('/api/protected', protectedRoutes); // Rate Limiting const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // Limit each IP to 100 requests per window message: 'Too many requests, please try again later.' }); app.use(limiter); mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true, }).then(() => console.log("MongoDB Connected")) .catch(err => console.error(err)); const httpsOptions = { key: fs.readFileSync('./key.pem'), cert: fs.readFileSync('./cert.pem') }; https.createServer(httpsOptions, app).listen(5000, () => console.log('Server running on port 5000 (HTTPS)')); 3. Implement Refresh Tokens Modify routes/authRoutes.js to include refresh tokens: const jwt = require('jsonwebtoken'); const refreshTokens = []; // Generate Access Token const generateAccessToken = (user) => { return jwt.sign({ id: user._id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '15m' }); }; // Generate Refresh Token const generateRefreshToken = (user) => { const refreshToken = jwt.sign({ id: user._id }, process.env.REFRESH_SECRET); refreshTokens.push(refreshToken); return refreshToken; }; // Refresh Token Route router.post('/refresh', (req, res) => { const { token } = req.body; if (!token || !refreshTokens.includes(token)) { return res.status(403).json({ message: 'Access denied' }); } jwt.verify(token, process.env.REFRESH_SECRET, (err, user) => { if (err) return res.status(403).json({ message: 'Invalid refresh token' }); const accessToken = generateAccessToken(user); res.json({ accessToken }); }); }); 4. Implement Role Management Modify routes/authRoutes.js to allow admin to change user roles: const { authenticate, authorize } = require('../middleware/authMiddleware'); // Change User Role (Admin Only) router.put('/change-role/:id', authenticate, authorize(['admin']), async (req, res) => { try { const { role } = req.body; const user = await User.findByIdAndUpdate(req.params.id, { role }, { new: true }); res.json({ message: 'User role updated', user }); } catch (err) { res.status(500).json({ error: 'Server error' }); } }); 5. Secure the API with HTTPS & Rate Limiting HTTPS: Uses SSL/TLS encryption Rate Limiting: Limits requests per IP 6. Test the API Start the server: node server.js Use Postman or cURL to test: Register a user: POST /api/auth/register Login to receive a token: POST /api/auth/login Get a new access token: POST /api/auth/refresh Change user role (Admin only): PUT /api/auth/change-role/:id Access protected routes: GET /api/protected/admin (Admin only) GET /api/protected/user (User and Admin) Conclusion You have successfully implemented Role-Based Authentication in Node.js Express with MongoDB. Key Features: ✔ Refresh tokens for session management ✔ Dynamic role management ✔ API security with HTTPS & rate limiting

Mar 15, 2025 - 20:44
 0
Role-Based Authentication in Node.js with Express.js and MongoDB

Introduction

Role-Based Authentication (RBA) is a method to control access based on user roles (e.g., Admin, User, Manager). This tutorial will guide you through implementing RBA in a Node.js application using Express.js and MongoDB.

Prerequisites

Before we start, ensure you have the following:

  • Node.js installed on your system
  • MongoDB set up and running
  • Basic knowledge of Express.js and JWT (JSON Web Tokens)
  • A tool like Postman or cURL for API testing

Steps to Implement Role-Based Authentication

1. Initialize the Project

First, create a new project folder and initialize a Node.js project.

mkdir role-based-auth
cd role-based-auth
npm init -y

This creates a package.json file for managing dependencies.

Now, install the required packages:

npm install express mongoose bcryptjs jsonwebtoken dotenv cors express-rate-limit https

express: Web framework for Node.js

mongoose: ODM (Object Data Modeling) library for MongoDB

bcryptjs: For hashing passwords securely

jsonwebtoken: To generate and verify authentication tokens

dotenv: For managing environment variables

cors: To enable Cross-Origin Resource Sharing

express-rate-limit: To prevent API abuse

https: For secure HTTPS implementation

2. Set Up the Server

Create server.js and configure the Express server:

require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const fs = require('fs');
const https = require('https');
const rateLimit = require('express-rate-limit');
const authRoutes = require('./routes/authRoutes');
const protectedRoutes = require('./routes/protectedRoutes');

const app = express();
app.use(express.json());
app.use('/api/auth', authRoutes);
app.use('/api/protected', protectedRoutes);

// Rate Limiting
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // Limit each IP to 100 requests per window
  message: 'Too many requests, please try again later.'
});
app.use(limiter);

mongoose.connect(process.env.MONGO_URI, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
}).then(() => console.log("MongoDB Connected"))
  .catch(err => console.error(err));

const httpsOptions = {
  key: fs.readFileSync('./key.pem'),
  cert: fs.readFileSync('./cert.pem')
};

https.createServer(httpsOptions, app).listen(5000, () => console.log('Server running on port 5000 (HTTPS)'));

3. Implement Refresh Tokens

Modify routes/authRoutes.js to include refresh tokens:

const jwt = require('jsonwebtoken');
const refreshTokens = [];

// Generate Access Token
const generateAccessToken = (user) => {
  return jwt.sign({ id: user._id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '15m' });
};

// Generate Refresh Token
const generateRefreshToken = (user) => {
  const refreshToken = jwt.sign({ id: user._id }, process.env.REFRESH_SECRET);
  refreshTokens.push(refreshToken);
  return refreshToken;
};

// Refresh Token Route
router.post('/refresh', (req, res) => {
  const { token } = req.body;
  if (!token || !refreshTokens.includes(token)) {
    return res.status(403).json({ message: 'Access denied' });
  }
  jwt.verify(token, process.env.REFRESH_SECRET, (err, user) => {
    if (err) return res.status(403).json({ message: 'Invalid refresh token' });
    const accessToken = generateAccessToken(user);
    res.json({ accessToken });
  });
});

4. Implement Role Management

Modify routes/authRoutes.js to allow admin to change user roles:

const { authenticate, authorize } = require('../middleware/authMiddleware');

// Change User Role (Admin Only)
router.put('/change-role/:id', authenticate, authorize(['admin']), async (req, res) => {
  try {
    const { role } = req.body;
    const user = await User.findByIdAndUpdate(req.params.id, { role }, { new: true });
    res.json({ message: 'User role updated', user });
  } catch (err) {
    res.status(500).json({ error: 'Server error' });
  }
});

5. Secure the API with HTTPS & Rate Limiting

  • HTTPS: Uses SSL/TLS encryption
  • Rate Limiting: Limits requests per IP

6. Test the API

Start the server:

node server.js

Use Postman or cURL to test:

  1. Register a user: POST /api/auth/register
  2. Login to receive a token: POST /api/auth/login
  3. Get a new access token: POST /api/auth/refresh
  4. Change user role (Admin only): PUT /api/auth/change-role/:id
  5. Access protected routes:
  6. GET /api/protected/admin (Admin only)
  7. GET /api/protected/user (User and Admin)

Conclusion

You have successfully implemented Role-Based Authentication in Node.js Express with MongoDB.

Key Features:
✔ Refresh tokens for session management
✔ Dynamic role management
✔ API security with HTTPS & rate limiting