DEV Community

Nadim Chowdhury
Nadim Chowdhury

Posted on

How to create an Authentication & Authorization feature in Express JS RESTful API?

Creating an authentication and authorization feature in an Express.js RESTful API involves several steps. Here's a step-by-step guide:

Step 1: Set Up a New Express.js Project

  1. Initialize a New Project:
   mkdir project-name
   cd project-name
   npm init -y
Enter fullscreen mode Exit fullscreen mode
  1. Install Required Packages:
   npm install express mongoose jsonwebtoken bcryptjs
   npm install dotenv passport passport-jwt
Enter fullscreen mode Exit fullscreen mode

Step 2: Configure Environment Variables

  1. Create a .env File:
   PORT=3000
   MONGODB_URI=mongodb://localhost:27017/auth-db
   JWT_SECRET=your_jwt_secret
Enter fullscreen mode Exit fullscreen mode
  1. Load Environment Variables: Create config.js to load environment variables:
   require('dotenv').config();

   module.exports = {
     port: process.env.PORT || 3000,
     mongodbUri: process.env.MONGODB_URI,
     jwtSecret: process.env.JWT_SECRET,
   };
Enter fullscreen mode Exit fullscreen mode

Step 3: Set Up Mongoose Models

  1. Create a Directory Structure:
   mkdir -p src/models src/controllers src/routes src/middleware
Enter fullscreen mode Exit fullscreen mode
  1. Create User Model: Create src/models/User.js:
   const mongoose = require('mongoose');
   const bcrypt = require('bcryptjs');

   const userSchema = new mongoose.Schema({
     username: {
       type: String,
       required: true,
       unique: true,
     },
     email: {
       type: String,
       required: true,
       unique: true,
     },
     password: {
       type: String,
       required: true,
     },
   });

   userSchema.pre('save', async function(next) {
     if (!this.isModified('password')) {
       return next();
     }
     const salt = await bcrypt.genSalt(10);
     this.password = await bcrypt.hash(this.password, salt);
     next();
   });

   userSchema.methods.matchPassword = async function(enteredPassword) {
     return await bcrypt.compare(enteredPassword, this.password);
   };

   const User = mongoose.model('User', userSchema);

   module.exports = User;
Enter fullscreen mode Exit fullscreen mode

Step 4: Set Up Controllers

  1. Create Auth Controller: Create src/controllers/authController.js:
   const jwt = require('jsonwebtoken');
   const User = require('../models/User');
   const config = require('../../config');

   const generateToken = (id) => {
     return jwt.sign({ id }, config.jwtSecret, { expiresIn: '1h' });
   };

   exports.registerUser = async (req, res) => {
     const { username, email, password } = req.body;

     const userExists = await User.findOne({ email });

     if (userExists) {
       return res.status(400).json({ message: 'User already exists' });
     }

     const user = await User.create({ username, email, password });

     if (user) {
       res.status(201).json({
         _id: user._id,
         username: user.username,
         email: user.email,
         token: generateToken(user._id),
       });
     } else {
       res.status(400).json({ message: 'Invalid user data' });
     }
   };

   exports.loginUser = async (req, res) => {
     const { email, password } = req.body;

     const user = await User.findOne({ email });

     if (user && (await user.matchPassword(password))) {
       res.json({
         _id: user._id,
         username: user.username,
         email: user.email,
         token: generateToken(user._id),
       });
     } else {
       res.status(401).json({ message: 'Invalid email or password' });
     }
   };

   exports.getUserProfile = async (req, res) => {
     const user = await User.findById(req.user.id);

     if (user) {
       res.json({
         _id: user._id,
         username: user.username,
         email: user.email,
       });
     } else {
       res.status(404).json({ message: 'User not found' });
     }
   };
Enter fullscreen mode Exit fullscreen mode

Step 5: Set Up Routes

  1. Create Auth Routes: Create src/routes/authRoutes.js:
   const express = require('express');
   const { registerUser, loginUser, getUserProfile } = require('../controllers/authController');
   const { protect } = require('../middleware/authMiddleware');

   const router = express.Router();

   router.post('/register', registerUser);
   router.post('/login', loginUser);
   router.get('/profile', protect, getUserProfile);

   module.exports = router;
Enter fullscreen mode Exit fullscreen mode

Step 6: Set Up Middleware

  1. Create Auth Middleware: Create src/middleware/authMiddleware.js:
   const jwt = require('jsonwebtoken');
   const User = require('../models/User');
   const config = require('../../config');

   exports.protect = async (req, res, next) => {
     let token;

     if (
       req.headers.authorization &&
       req.headers.authorization.startsWith('Bearer')
     ) {
       try {
         token = req.headers.authorization.split(' ')[1];

         const decoded = jwt.verify(token, config.jwtSecret);

         req.user = await User.findById(decoded.id).select('-password');

         next();
       } catch (error) {
         res.status(401).json({ message: 'Not authorized, token failed' });
       }
     }

     if (!token) {
       res.status(401).json({ message: 'Not authorized, no token' });
     }
   };
Enter fullscreen mode Exit fullscreen mode

Step 7: Set Up the Express Server

  1. Create the Server: Create src/index.js:
   const express = require('express');
   const mongoose = require('mongoose');
   const bodyParser = require('body-parser');
   const config = require('../config');
   const authRoutes = require('./routes/authRoutes');

   const app = express();

   mongoose.connect(config.mongodbUri, {
     useNewUrlParser: true,
     useUnifiedTopology: true,
     useCreateIndex: true,
   }).then(() => {
     console.log('Connected to MongoDB');
   }).catch((err) => {
     console.error('Error connecting to MongoDB', err);
   });

   app.use(bodyParser.json());
   app.use('/api/auth', authRoutes);

   app.listen(config.port, () => {
     console.log(`Server running on http://localhost:${config.port}`);
   });
Enter fullscreen mode Exit fullscreen mode

Step 8: Test the API

  1. Register a User:
   POST /api/auth/register
   Content-Type: application/json

   {
     "username": "john",
     "email": "john@example.com",
     "password": "password"
   }
Enter fullscreen mode Exit fullscreen mode
  1. Login a User:
   POST /api/auth/login
   Content-Type: application/json

   {
     "email": "john@example.com",
     "password": "password"
   }
Enter fullscreen mode Exit fullscreen mode
  1. Get User Profile (Protected Route):
   GET /api/auth/profile
   Authorization: Bearer <token>
Enter fullscreen mode Exit fullscreen mode

This guide provides a foundational approach to implementing authentication and authorization in an Express.js RESTful API. You can further expand and customize it based on your application's requirements.

Disclaimer: This content is generated by AI.

Top comments (0)