Zum Hauptinhalt springen
Intelligence View
⚡ tsecurity.de Intelligence

Implementing an Express-based REST API in TypeScript with MongoDB, JWT-based Authentication, and RBAC

Implementing an Express-based REST API in TypeScript with MongoDB, JWT-based Authentication, and Role-Based Access Control (RBAC)

Creating a robust REST API requires proper architecture, authentication mechanisms, and database integration. This article will guide you through building an Express-based REST API in TypeScript with MongoDB, JWT-based Authentication, and Role-Based Access Control (RBAC).

Prerequisites

  • Node.js and npm installed.
  • Basic understanding of TypeScript, Express, and MongoDB.
  • MongoDB instance (local or cloud, e.g., MongoDB Atlas).

Step 1: Project Setup

1. Initialize the Project

Run the following commands to set up the project:

mkdir express-api-rbac
cd express-api-rbac
npm init -y
npm install typescript ts-node nodemon --save-dev
npm install express mongoose jsonwebtoken bcrypt dotenv cors
npm install @types/express @types/mongoose @types/jsonwebtoken @types/node --save-dev

2. Configure TypeScript

Create a tsconfig.json file:

{
    "compilerOptions": {
        "target": "ES6",
        "allowSyntheticDefaultImports": true,
        "esModuleInterop": true,
        "outDir": "dist",
        "forceConsistentCasingInFileNames": true,
        "strict": true,
        "skipLibCheck": true,
        "types": ["jest"],
        "moduleResolution": "Node16",
        "module": "Node16"
    },
    "exclude": ["node_modules/"],
    "include": ["src/**/*.ts", "test/**/*.ts"]
}

3. Project Structure

Organize your project as follows:

src/
├── server.ts
├── config/
│   └── config.ts
├── models/
│   └── user.model.ts
├── middleware/
│   ├── auth.middleware.ts
│   └── corsHandler.ts
|   └── loggingHandler.ts
|   └── routeNotFound.ts
├── routes/
│   ├── auth.routes.ts
│   └── user.routes.ts
├── controllers/
│   └── auth.controller.ts
|   └── user.controller.ts
└── utils/
    └── logging.ts

Step 2: Configure MongoDB and other Server configuration

Database Configuration

src/config/config.ts:

import dotenv from 'dotenv';
import mongoose from 'mongoose';
dotenv.config();

export const DEVELOPMENT = process.env.NODE_ENV === 'development';
export const TEST = process.env.NODE_ENV === 'test';

export const MONGO_USER = process.env.MONGO_USER || '';
export const MONGO_PASSWORD = process.env.MONGO_PASSWORD || '';
export const MONGO_URL = process.env.MONGO_URL || '';
export const MONGO_DATABASE = process.env.MONGO_DATABASE || '';
export const MOGO_OPTIONS: mongoose.ConnectOptions = { retryWrites: true, w: 'majority' };

export const SERVER_HOSTNAME = process.env.SERVER_HOSTNAME || 'localhost';
export const SERVER_PORT = process.env.SERVER_PORT ? Number(process.env.SERVER_PORT) : 12345;

export const JWT_SECRET = process.env.JWT_SECRET || 'secret_key';

export const mongo = {
    MONGO_USER,
    MONGO_PASSWORD,
    MONGO_URL,
    MONGO_DATABASE,
    MOGO_OPTIONS,
    MONGO_CONNECTION: `mongodb+srv://${MONGO_USER}:${MONGO_PASSWORD}@${MONGO_DATABASE}.${MONGO_URL}`
};

export const server = {
    SERVER_HOSTNAME,
    SERVER_PORT
};

Connecting to MongoDB

src/server.ts:

import http from 'http';
import express from 'express';
import mongoose from 'mongoose';
import './config/logging';
import { corsHandler } from './middleware/corsHandler';
import { loggingHandler } from './middleware/loggingHandler';
import { routeNotFound } from './middleware/routeNotFound';
import { server, mongo } from './config/config';
import userRouter from './routes/user.routes';
import authRouter from './routes/auth.routes';
export const application = express();
export let httpServer: ReturnType<typeof http.createServer>;

let isConnected = false;

export const Main = async () => {
    logging.log('----------------------------------------');
    logging.log('Initializing API');
    logging.log('----------------------------------------');
    application.use(express.urlencoded({ extended: true }));
    application.use(express.json());

    logging.log('----------------------------------------');
    logging.log('Connect to DB');
    logging.log('----------------------------------------');

    try {
        logging.log('MONGO_CONNECTION: ', mongo.MONGO_CONNECTION);
        if (isConnected) {
            logging.log('----------------------------------------');
            logging.log('Using existing connection');
            logging.log('----------------------------------------');
            return mongoose.connection;
        }

        const connection = await mongoose.connect(mongo.MONGO_CONNECTION, mongo.MOGO_OPTIONS);
        isConnected = true;
        logging.log('----------------------------------------');
        logging.log('Connected to db', connection.version);
        logging.log('----------------------------------------');
    } catch (error) {
        logging.log('----------------------------------------');
        logging.log('Unable to connect to db');
        logging.error(error);
        logging.log('----------------------------------------');
    }

    logging.log('----------------------------------------');
    logging.log('Logging & Configuration');
    logging.log('----------------------------------------');
    application.use(loggingHandler);
    application.use(corsHandler);

    logging.log('----------------------------------------');
    logging.log('Define Controller Routing');
    logging.log('----------------------------------------');
    application.get('/main/healthcheck', (req, res, next) => {
        return res.status(200).json({ hello: 'world!' });
    });

    application.use('/api/users', userRouter);
    application.use('/api/auth', authRouter);

    logging.log('----------------------------------------');
    logging.log('Define Routing Error');
    logging.log('----------------------------------------');
    application.use(routeNotFound);

    logging.log('----------------------------------------');
    logging.log('Starting Server');
    logging.log('----------------------------------------');
    httpServer = http.createServer(application);
    httpServer.listen(server.SERVER_PORT, () => {
        logging.log('----------------------------------------');
        logging.log(`Server started on ${server.SERVER_HOSTNAME}:${server.SERVER_PORT}`);
        logging.log('----------------------------------------');
    });
};

export const Shutdown = () => {
    return new Promise((resolve, reject) => {
        if (httpServer) {
            httpServer.close((err) => {
                if (err) return reject(err);
                resolve(true);
            });
        } else {
            resolve(true);
        }
    });
};

Main();

Step 3: Create the User Model

src/models/user.model.ts:

import mongoose, { Schema } from 'mongoose';

export type UserRole = 'admin' | 'distributor' | 'retailer';

export interface IUser extends Document {
    role: UserRole;
    hash: string;
    name: string;
    email: string;
    password: string;
    contact: string;
    business_name: string;
    address: {
        line1: string;
        city: string;
        state: string;
        zipcode: string;
    };
    geolocation?: { lat: number; long: number };
}

const UserSchema: Schema = new Schema(
    {
        role: { type: String, enum: ['admin', 'distributor', 'retailer'], required: true },
        hash: { type: String },
        name: { type: String, required: true },
        email: { type: String, required: true, unique: true },
        password: { type: String, required: true },
        contact: { type: String, required: true },
        business_name: { type: String, required: true },
        address: {
            line1: String,
            city: String,
            state: String,
            zipcode: String
        },
        geolocation: {
            lat: Number,
            long: Number
        }
    },
    {
        timestamps: true
    }
);

const User = mongoose.model<IUser>('User', UserSchema);

export default User;

Step 4: Implement Middleware

Authentication Middleware

src/middleware/auth.middleware.ts:

import { NextFunction, Request, Response } from 'express';
import jwt from 'jsonwebtoken';

import { IUser, UserRole } from '../models/user.model';
import { JWT_SECRET } from '../config/config';
import mongoose from 'mongoose';

export interface JwtRequest extends Request {
    user?: {
        email: string;
        role: UserRole;
    };
}

export const authentication = (req: JwtRequest, res: Response, next: NextFunction) => {
    const authHeader = req.headers.authorization;
    if (!authHeader) {
        return res.status(401).json('No authorization header found');
    }

    const token = authHeader.split(' ')[1]; // Token structure is 'Bearer <token>'
    try {
        const decoded = jwt.verify(token, JWT_SECRET);
        req.user = decoded as IUser;
        next();
    } catch (error) {
        return res.status(401).json('Invalid token');
    }
};

export function authorizeRoles(allowedRoles: UserRole[]) {
    return (req: JwtRequest, res: Response, next: NextFunction) => {
        const user = req.user;

        if (user && !allowedRoles.includes(user.role)) {
            return res.status(403).json({ message: `Forbidden, you are a ${user.role} and this service is only available for ${allowedRoles}` });
        }

        next();
    };
}

export const generateToken = (_id: mongoose.Types.ObjectId, role: string) => {
    return jwt.sign({ _id, role }, JWT_SECRET, { expiresIn: '1h' });
};

Step 5: Create Routes

Authentication Routes

src/routes/auth.routes.ts:

import express, { Router } from 'express';
import { registerUser, loginUser } from '../controllers/auth.controller';

const authRouter: Router = express.Router();

/**
 * @route   POST /api/auth/register
 * @desc    Create a new user
 * @access  (Public)
 */
authRouter.post('/register', registerUser);

/**
 * @route   POST /api/auth/login
 * @desc    Login a user and get token
 * @access  (Public)
 */
authRouter.post('/login', loginUser);

export default authRouter;

Protected Routes

src/routes/user.routes.ts:

import express, { Router } from 'express';
import { protectedRoute, deleteUser, getUserById, updateUser } from '../controllers/user.controller';
import { authentication, authorizeRoles } from '../middleware/auth.middleware';
const userRouter: Router = express.Router();

/**
 * @route   GET /api/users/protected
 * @desc    A protected route
 * @access  Admin/Distributor/Retailer
 */
userRouter.get('/protected', authentication, protectedRoute);

/**
 * @route   GET /api/users/:id
 * @desc    Get a user by email
 * @access  Admin/Distributor/Retailer (self)
 */
userRouter.get('/:id', authentication, getUserById);

/**
 * @route   DELETE /api/users/:id
 * @desc    Delete a user
 * @access  Admin
 */
userRouter.delete('/:id', authentication, authorizeRoles(['admin']), deleteUser);

/**
 * @route   PUT /users/:id
 * @desc    Update user details
 * @access  Admin/Distributor/Retailer (self)
 */
userRouter.put('/:id', authentication, updateUser);

export default userRouter;

Step 6: Create Controllers

src/controllers/auth.controller.ts:

import { Request, Response } from 'express';
import bcrypt from 'bcrypt';
import User from '../models/user.model';
import { generateToken } from '../middleware/auth.middleware';

//User registration
export const registerUser = async (req: Request, res: Response) => {
    console.log('Register route hit');
    try {
        const { name, email, password, role, contact, business_name, address, geolocation } = req.body;
        const hashedPassword = await bcrypt.hash(password, 10);
        const user = new User({ name, email, password: hashedPassword, role, contact, business_name, address, geolocation });
        await user.save();
        return res.status(201).json({ message: 'User created' });
    } catch (error: any) {
        res.status(400).json({ error: error.message });
    }
};

//User login
export const loginUser = async (req: Request, res: Response) => {
    try {
        const { email, password } = req.body;
        const user = await User.findOne({ email });
        if (!user) {
            return res.status(404).json({ error: 'User does not exist' });
        }
        const isPasswordValid = await bcrypt.compare(password, user.password);
        if (!isPasswordValid) {
            return res.status(401).json({ error: 'Invalid email or password' });
        }
        const token = generateToken(user._id, user.role);
        return res.status(200).json({ token });
    } catch (error: any) {
        res.status(500).json({ error: error.message });
    }
};

Step 7: Start the Server

Run the following command to start the server:

npm run dev

The full source code is available at: https://github.com/syedammar/rest-api-nodejs-typescript

This implementation provides a modular, maintainable API with authentication and role-based access control. You can expand it by adding more routes, models, and business logic as required.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Implementing an Express-based REST API in TypeScript with MongoDB, JWT-based Authentication, and RBAC

Thematisch verwandte Begriffe: Implementing, Expressbased, REST, TypeScript · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-61591 | djust provides Phoenix LiveView-style reactive server-side rendering for…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
News ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

↗ Original-Quelle