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



This content originally appeared on DEV Community and was authored by Haque.

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


This content originally appeared on DEV Community and was authored by Haque.