DEV Community

FredAbod
FredAbod

Posted on • Updated on

Hashing Password And Generating User Token In Your Schema

Hashing Password And Generating User Token In Your Schema

Let's dive right into it

Dive

I know you must be asking yourself, Why Do we need to Hash our Password in the schema rather than doing it in our controller logic or the routes?
I'll give you very simple answers:

  1. If you need to hash Password in a couple of places in your code this Is a better approach
  2. If you need to assign a token in more than one route in your application this Is a better approach > I actually feel this approach is cool πŸ˜πŸ˜πŸ˜‹πŸ˜‹πŸ˜ŽπŸ˜Ž

So Lets Go

Step 1 Project Setup

Create a new directory for your project and initialize it with npm:

mkdir hashing-password-schema
cd hashing-password-schema
npm init -y
Enter fullscreen mode Exit fullscreen mode

Step 2: We'll Install Our Project Dependencies

npm install express mongoose dotenv morgan bcryptjs jsonwebtoken
Enter fullscreen mode Exit fullscreen mode

Step 3: We'll Create Our Entry File, dotenv and gitignore file

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

Step 4: We'll Create an src folder with controller config models and routes folders

mkdir src src/models src/controller src/config src/routes
Enter fullscreen mode Exit fullscreen mode

Step 5: We'll edit our index.js file

Don't worry I added comments to every line of the code

 // Importing required modules and packages
 const express = require("express"); // Express framework for building web applications
 const dotenv = require("dotenv"); // Dotenv for managing environment variables
 const morgan = require("morgan"); // Morgan for HTTP request logging


 // Initializing the Express application
 const app = express();

 // Middleware to parse incoming JSON data
 app.use(express.json());

 // Loading environment variables from .env file
 dotenv.config();

 // Middleware for HTTP request logging in development mode
 app.use(morgan("dev"));

 // Setting the port for the server to listen on
 const port = process.env.PORT || 3000;

 // Handling GET requests to the root route
 app.get("/", (req, res) => {
   res.send("Welcome To Our Tutorial");
 });


 // Handling 404 errors with a custom message
 app.get("*", (req, res) => {
     res.status(404).json("page not found");
   });

 // Starting the server and connecting to the MongoDB database
 app.listen(port, async () => {
     console.log(`Server is listening on http://localhost:${port}`);
   });
Enter fullscreen mode Exit fullscreen mode

Make sure you configure your package.json file to have this scripts

"scripts": {
    "dev": "nodemon index.js"
  },
Enter fullscreen mode Exit fullscreen mode

Now we do npm run dev and get this Server is listening on http://localhost:5000
If you access that route you should see Welcome To Our Tutorial

Step 6: We'll create a db.js file in the config folder and add these lines of code

const mongoose = require('mongoose');

 exports.connectDB = (url)=> {
    return mongoose.connect(url)
};
Enter fullscreen mode Exit fullscreen mode

Let's not forget to add our config files to our .env file

PORT= 5000
MONGODB_URL= mongodb://localhost:27017/tutorial
Enter fullscreen mode Exit fullscreen mode

Step 6: Let's Import Our Database Configuration File in our index.js file, It should now look like this:

// Importing required modules and packages
const express = require("express"); // Express framework for building web applications
const dotenv = require("dotenv"); // Dotenv for managing environment variables
const mongoose = require("mongoose"); // Mongoose for MongoDB object modeling
const morgan = require("morgan"); // Morgan for HTTP request logging

// Importing the connectDB function from the db configuration file
const { connectDB } = require("./src/config/db");

// Initializing the Express application
const app = express();

// Middleware to parse incoming JSON data
app.use(express.json());

// Loading environment variables from .env file
dotenv.config();

// Middleware for HTTP request logging in development mode
app.use(morgan("dev"));

// Setting the port for the server to listen on
const port = process.env.PORT || 3000;

// Handling GET requests to the root route
app.get("/", (req, res) => {
  res.send("Welcome To Our TODO LIST APP");
});

// Handling 404 errors with a custom message
app.get("*", (req, res) => {
  res.status(404).json("page not found");
});

// Starting the server and connecting to the MongoDB database
app.listen(port, async () => {
  try {
    // Connecting to the MongoDB database using the connectDB function
    await connectDB(process.env.MONGODB_URL);
    console.log("Database connection established");
    console.log(`Server is listening on http://localhost:${port}`);
  } catch (error) {
    // Handling errors during database connection
    console.log("Error connecting to MongoDB: " + error.message);
  }
});
Enter fullscreen mode Exit fullscreen mode

And You should have this Database connection established
Server is listening on http://localhost:5000
from your terminal

Step 7: Lets create a user.Models.js file in the models folder. Then we'll perform the magic

// Importing required modules and packages
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");

// Defining the user schema
const userSchema = new mongoose.Schema(
  {
    userName: {
      type: String,
      required: [true, "Username is required"],
    },
    email: {
      type: String,
      required: [true, "Email is required"],
      unique: true,
      lowercase: true,
      trim: true,
    },
    password: {
      type: String,
      required: [true, "Password is required"],
    },
  },
  { timestamps: true, versionKey: false }
);

// Hash the password before saving
userSchema.pre("save", async function (next) {
  try {
    const salt = await bcrypt.genSalt(10);
    const hashedPassword = await bcrypt.hash(this.password, salt);
    this.password = hashedPassword;
    next();
  } catch (error) {
    next(error);
  }
});

// Generate JWT token
userSchema.methods.generateAuthToken = function () {
  const token = jwt.sign({ _id: this._id }, process.env.SECRET_KEY, {
    expiresIn: process.env.EXPIRES_IN, // You can adjust the expiration time
  });
  return token;
};

// Creating the User model using the user schema
const User = mongoose.model("User", userSchema);

// Exporting the User model
module.exports = User;
Enter fullscreen mode Exit fullscreen mode

Now we need to add some config to our .env file:

SECRET_KEY = kagdkdgajhkdgfajkhdfgjkdf862d82d86d528275
EXPIRES_IN = 1h
Enter fullscreen mode Exit fullscreen mode

Step 8: Now we create a user.Controller.js file in the controller folder and add our signup and login

// Importing required modules and packages
const User = require('../models/user.Models');
const bcrypt = require('bcryptjs');

// Function to check if the user with the given email already exists
const checkExistingUser = async (email) => {
  return User.findOne({ email });
};

// Signup function for user registration
const signUp = async (req, res, next) => {
  try {
    const { userName, email, password } = req.body;

    // Validation for required input fields
    if (!userName || !email || !password) {
      return res.status(400).json({
        error: 'Invalid input',
        message: 'Please enter a username, email address, and password.',
      });
    }

    // Check if user with the same email already exists
    const existingUser = await checkExistingUser(email);
    if (existingUser) {
      return res.status(400).json({
        error: 'User already exists',
        message: 'A user with this email address already exists.',
      });
    }

    // Create a new user
    const newUser = await User.create({
      userName,
      email,
      password,
    });

    return res.status(201).json({
      success: true,
      message: 'User created successfully',
      data: newUser,
    });
  } catch (error) {
    next(error); // Pass the error to the error-handling middleware
  }
};

// Login function for user authentication
const loginUser = async (req, res, next) => {
  try {
    const { email, password } = req.body;

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

    if (!user) {
      return res.status(404).json({ error: 'User not found', message: 'Invalid credentials' });
    }

    // Compare passwords
    const isPasswordMatch = await bcrypt.compare(password, user.password);

    if (!isPasswordMatch) {
      return res.status(401).json({ error: 'Invalid password', message: 'Invalid credentials' });
    }

    // Generate JWT token
    const token = user.generateAuthToken();

    res.status(200).json({ success: true, token });
  } catch (error) {
    next(error);
  }
};

// Exporting the signup and login functions
module.exports = { signUp, loginUser };
Enter fullscreen mode Exit fullscreen mode

I know you GET right 😎😎

Step 9: We'll create a user.Routes.js file in our routes folder and add these:

// Importing required modules and packages
const express = require("express");
const router = express.Router();
const { loginUser, signUp } = require("../controller/user.Controller");

// Endpoint for user registration
router.post("/signup", signUp);

// Endpoint for user login
router.post("/login", loginUser);

// Exporting the router for use in other modules
module.exports = router;
Enter fullscreen mode Exit fullscreen mode

Step 10: Now we'll import our userRoutes into index.js file:

// Importing user routes
const userRoutes = require('./src/routes/user.Routes');
// Using user routes for endpoints starting with '/api/v1/user'
app.use('/api/v1/user', userRoutes)
Enter fullscreen mode Exit fullscreen mode

Make sure you add those lines of code to the index.js file

Step 11: Now we test 😁😁😁😁

You can use any testing and I have decided to use thunderclient It's an extension on Visual Studio Code

Use this route for signUp http://localhost:5000/api/v1/user/signup make sure it's a POST request

Thunder Client

DB

Now Let's try login http://localhost:5000/api/v1/user/login

Login

And We're Done πŸ˜‹πŸ˜‹πŸ˜‹
I hope This was Insightful, please leave a Like, a follow and leave your questions in the comment section πŸ₯°πŸ₯°.
Here is the github repo for the tutorial

Bow

Top comments (0)