Hashing Password And Generating User Token In Your Schema
Let's dive right into it
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:
- If you need to hash Password in a couple of places in your code this Is a better approach
- 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
Step 2: We'll Install Our Project Dependencies
npm install express mongoose dotenv morgan bcryptjs jsonwebtoken
Step 3: We'll Create Our Entry File, dotenv and gitignore file
touch index.js .env .gitignore
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
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}`);
});
Make sure you configure your
package.json
file to have this scripts
"scripts": {
"dev": "nodemon index.js"
},
Now we do
npm run dev
and get thisServer is listening on http://localhost:5000
If you access that route you should seeWelcome 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)
};
Let's not forget to add our config files to our
.env
file
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:
// 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
from your terminal
Server is listening on http://localhost:5000
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;
Now we need to add some config to our
.env
file:
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
// 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:
// 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:
// 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
Now Let's try login
http://localhost:5000/api/v1/user/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
Top comments (0)