DEV Community

Cover image for Authentication( SignUp and Login ) with Express,MongoDB and Jwt.
FredAbod
FredAbod

Posted on

Authentication( SignUp and Login ) with Express,MongoDB and Jwt.

In this article, I'll walk through the process of setting up user authentication using Express, MongoDB, and JSON Web Tokens (JWT). This will allow you to implement user signup, login, and protect routes that require authentication.

Let's Dive Right In 😁😁

Dive In

Prerequisites

Make sure you have Node.js installed on your machine. Additionally, create a new directory for your project and initialize it with the following dependencies:

npm init -y
npm install express mongoose dotenv jsonwebtoken bcrypt
Enter fullscreen mode Exit fullscreen mode

This process should look like this:
cmd

Create your main entry file, .env and .gitignore if you wish to push your code

touch index.js .env .gitignore
Enter fullscreen mode Exit fullscreen mode

Project Setup

  1. We'll import our packages into index.js and setup our express server.
const express = require('express');
const dotenv = require('dotenv');

dotenv.config();

const app = express();
const PORT = process.env.PORT || 3000;


app.use(express.json());

app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

Make sure your script is set in your package.json. Now when I do npm run dev on my terminal I should have Server is running on port 5500
And do not forget to also declare your PORT in the .env file.

  1. I would quickly 😋😋 add a root entry file > Now my code looks like this
const express = require('express');
const dotenv = require('dotenv');

dotenv.config();

const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());

app.get('/', (req, res)=> {
    res.send('Welcome to Nodejs Authentication Tutorial')
})

app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode
  1. I'll create a folder called config to hold my database file which I would call database.js > Now I would configure my database, my database.js folder would look like this:
const mongoose = require('mongoose');

exports.connectDb = async () => {
  try {
    await mongoose.connect(process.env.MONGODB_URI);
    console.log("MongoDB connection Established...");
  } catch (error) {
    console.error(error.message);
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. I would import the database function into the index.js file and fire it. > Your index.js file should look like this now
const express = require("express");
const dotenv = require("dotenv");
const { connectDb } = require("./config/database");

dotenv.config();

const app = express();
const PORT = process.env.PORT || 3000;

// Iinitialized Database Configuration
connectDb();

app.use(express.json());

// Root Entry 
app.get("/", (req, res) => {
  res.send("Welcome to Nodejs Authentication Tutorial");
});

// Listened to the PORT
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode
  1. Let's define our user Schema For Mongodb, we'll be accepting just two fields username and password > We'll create a folder called models and a file called userModels.js > My userModels.js file looks like this now
const mongoose = require('mongoose');


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

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

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

Whew

  1. Now let's create a folder called controller and a file called userController.js > Now Your userController.js should look like this
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const User  = require("../models/userModels");

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

    // Check If The Input Fields are Valid
    if (!username || !password) {
      return res
        .status(400)
        .json({ message: "Please Input Username and Password" });
    }

    // Check If User Exists In The Database
    const existingUser = await User.findOne({ username });

    if (existingUser) {
      return res.status(400).json({ message: "User Already Exists" });
    }

    // Hash The User's Password
    const saltRounds = 10;
    const hashedPassword = await bcrypt.hash(password, saltRounds);

    // Save The User To The Database
    const newUser = new User({
      username,
      password: hashedPassword,
    });

    await newUser.save();

    return res
      .status(201)
      .json({ message: "User Created Successfully", newUser });
  } catch (error) {
    console.log(error.message);
    return res.status(500).json({ message: "Error creating user" });
  }
};

Enter fullscreen mode Exit fullscreen mode
  1. Now we create our routes folder and user.Routes.js file > Now the user.Routes.js file should look like this;
const express = require('express');
const { signUp } = require('../controller/userController');
const router = express.Router();

router.post('/signup', signUp);

module.exports = router;
Enter fullscreen mode Exit fullscreen mode
  1. We'll import our Router into the index.js file > We'll add these two lines of code to our index.js file
const userRouter = require("./routes/user.Routes");
app.use("/api/v1/user", userRouter);
Enter fullscreen mode Exit fullscreen mode

Now index.js Should look like this

const express = require("express");
const dotenv = require("dotenv");
const { connectDb } = require("./config/database");
const userRouter = require("./routes/user.Routes");

dotenv.config();

const app = express();
const PORT = process.env.PORT || 3000;

// Iinitialized Database Configuration
connectDb();

app.use(express.json());

// Import The User Route
app.use("/api/v1/user", userRouter);

// Root Entry
app.get("/", (req, res) => {
  res.send("Welcome to Nodejs Authentication Tutorial");
});

// Listened to the PORT
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

Now Let's Test, I would be using thunder client
You test with this route http://localhost:5500/api/v1/user/signup

Testing Signup

You can install MongoDB compass to also check

Database Check

Now We Can Try Login

Right inside your userController.js we'll write the lines of code for login. And That Should Look like this

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

    // Check If The Input Fields are Valid
    if (!username || !password) {
      return res
        .status(400)
        .json({ message: "Please Input Username and Password" });
    }

    // Check If User Exists In The Database
    const user = await User.findOne({ username });

    if (!user) {
      return res.status(401).json({ message: "Invalid username or password" });
    }

    // Compare Passwords
    const passwordMatch = await bcrypt.compare(password, user.password);

    if (!passwordMatch) {
      return res.status(401).json({ message: "Invalid username or password" });
    }

    // Generate JWT Token
    const token = jwt.sign(
      { userId: user._id, username: user.username },
      process.env.SECRET_KEY || "1234!@#%<{*&)",
      { expiresIn: "1h" }
    );

    return res
      .status(200)
      .json({ message: "Login Successful", data: user, token });
  } catch (error) {
    console.log(error.message);
    return res.status(500).json({ message: "Error during login" });
  }
};
Enter fullscreen mode Exit fullscreen mode
  1. We need to add login to our user.Routes.js file
const express = require('express');
const { signUp, login } = require('../controller/userController');
const router = express.Router();

router.post('/signup', signUp);
router.post('/login', login);

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

Now we Test Our Login at http://localhost:5500/api/v1/user/login

Login Test

So we Unhashed the password, logged and Attached Jwt to the User successfully.

Yay

Lets Do One Last thing Let's Find all Users But we'll make the Route Protected by Jwt

So we'll add this to the userController.js file

exports.getAllUsers = async (req, res) => {
  try {
    // Retrieve all users from the database
    const users = await User.find({}, { password: 0 }); // Exclude the password field from the response

    return res.status(200).json({ users });
  } catch (error) {
    console.log(error.message);
    return res.status(500).json({ message: "Error fetching users" });
  }
};
Enter fullscreen mode Exit fullscreen mode

We'll add this to the routes

const express = require('express');
const { signUp, login, getAllUsers } = require('../controller/userController');
const router = express.Router();

router.GET('/allusers', getAllUsers);
router.post('/signup', signUp);
router.post('/login', login);

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

When you test on http://localhost:5500/api/v1/user/allusers You should get All the users you have in your Database

Now can protect this route with our Jwt Token, Let's create a file called isAuth.js in our config folder and it would look like this

const jwt = require("jsonwebtoken");

exports.verifyToken = async (req, res, next) => {
  try {
    const token = req.headers.authorization.split(" ")[1];
    if (!token) {
      return res.status(401).json({ error: "Unauthorized" });
    }
    const decoded = await jwt.verify(token, process.env.SECRET_KEY);
    if (!decoded) {
      throw new Error();
    }
    req.user = decoded;

    next();
  } catch (error) {
    console.log(error);
    return res.status(500).json({ message: "Error Validating Token" });
  }
};

Enter fullscreen mode Exit fullscreen mode

Now we need to import verifyToken into our Route
And now our Route looks like this

const express = require('express');
const { signUp, login, getAllUsers } = require('../controller/userController');
const { verifyToken } = require('../config/isAuth');
const router = express.Router();

router.get('/allusers', verifyToken, getAllUsers);
router.post('/signup', signUp);
router.post('/login', login);

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

And We Are Done

Here's a Link To The Github repo for this Project
Please leave a Like And A Comment If This Article Was Helpful And Probably you have any questions. Untill Next Time

Bow

Top comments (0)