Hashing Password And Generating User Token In Your Schema
Tags: javascript, node, mongodb, programming
Published: 2024-02-28 17:47:05

## Hashing Password And Generating User Token In Your Schema

Let's dive right into it

![Dive](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9vupjpbusutuhabcsl78.gif)

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:

```bash
mkdir hashing-password-schema
cd hashing-password-schema
npm init -y
```

## Step 2: We'll Install Our Project Dependencies
```bash
npm install express mongoose dotenv morgan bcryptjs jsonwebtoken
```
## Step 3: We'll Create Our Entry File, dotenv and gitignore file
```bash
touch index.js .env .gitignore
```

## Step 4: We'll Create an `src` folder with controller config models and routes folders
```bash
mkdir src src/models src/controller src/config src/routes
```

## Step 5: We'll edit our index.js file 
> Don't worry I added comments to every line of the code
```javascript
 // 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}`);
   });
```
> Make sure you configure your `package.json` file to have this scripts
```bash
"scripts": {
    "dev": "nodemon index.js"
  },
```
> 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
```javascript
const mongoose = require('mongoose');

 exports.connectDB = (url)=> {
    return mongoose.connect(url)
};
```
> Let's not forget to add our config files to our `.env` file
```bash
PORT= 5000
MONGODB_URL= mongodb://localhost:27017/tutorial
```
## Step 6: Let's Import Our Database Configuration File in our `index.js` file, It should now look like this:
```javascript
// 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);
  }
});
```
> 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
```javascript
// 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;
```
> Now we need to add some config to our `.env` file:
```bash
SECRET_KEY = kagdkdgajhkdgfajkhdfgjkdf862d82d86d528275
EXPIRES_IN = 1h
```
## Step 8: Now we create a `user.Controller.js` file in the controller folder and add our `signup` and `login`
```javascript
// 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 };
```
> I know you GET right 😎😎

## Step 9: We'll create a `user.Routes.js` file in our routes folder and add these:
```javascript
// 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;
```
## Step 10: Now we'll import our userRoutes into `index.js` file:
```javascript
// 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)
```
> 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bmsulfd4k5kulej7ew10.png)

![DB](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ltjuwtcj0zq999mefq9u.png)

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

![Login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v1j8eujaoe3jco8hg0or.png)

> 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](https://github.com/FredAbod/MongooseTutorial) for the tutorial


![Bow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uztm67opawiuif6hmal8.gif)