Create Modals¶
-
unverified user schema
import mongoose, { Schema } from "mongoose"; import bcrypt from "bcrypt"; const unverifiedUserSchema = new Schema( { name: { type: String, required: true, }, email: { type: String, required: true, unique: true, }, password: { type: String, required: true, }, }, { timestamps: true } ); unverifiedUserSchema.methods.matchPassword = async function (enteredPassword) { return await bcrypt.compare(enteredPassword, this.password); }; unverifiedUserSchema.pre("save", async function (next) { if (!this.isModified("password")) { next(); } this.password = await bcrypt.hash(this.password, 12); }); export const UnverifiedUser = mongoose.model("UnverifiedUser", unverifiedUserSchema);
-
user schema
import mongoose, { Schema } from "mongoose"; import bcrypt from "bcrypt"; const userSchema = new Schema( { name: { type: String, required: true, }, email: { type: String, required: true, unique: true, }, password: { type: String, required: true, }, companies: [ { type: Schema.Types.ObjectId, ref: "Company", }, ], }, { timestamps: true } ); userSchema.methods.matchPassword = async function (enteredPassword) { console.log("Entered Password:", enteredPassword); const temp = await bcrypt.hash(enteredPassword, 12); console.log("Temp: ", temp); console.log("Password: ", this.password); return await bcrypt.compare(enteredPassword, this.password); }; userSchema.pre("save", async function (next) { if (!this.isModified("password") || this.isNew) { next(); } this.password = await bcrypt.hash(this.password, 12); }); export const User = mongoose.model("User", userSchema);
Create Nodemailer file¶
- inside util create file named send mail.js
import nodemailer from "nodemailer"; import dotenv from "dotenv"; dotenv.config(); const transporter = nodemailer.createTransport({ service: "gmail", host: "smtp.gmail.com", port: 465, auth: { user: process.env.EMAIL_ID, pass: process.env.APP_PASSWORD, }, }); const sendConfirmationMail = async (to, id) => { const mailOptions = { from: process.env.EMAIL_ID, to: [to], subject: "Email Verification for MERN Chat App", html: `<h1>Click <a href=http://localhost:5000/api/auth/confirmEmail/${id}>here</a> to confirm your email</h1>`, }; try { await transporter.sendMail(mailOptions); console.log("Verification Email sent succesfully"); return true; } catch (error) { console.log("Error while sending verification email", error); return false; } }; export { sendConfirmationMail };
- Don't forget to put things in .env
Create Routes¶
- create auth.routes.js and auth.controller.js with /api/auth/login /api/auth/register etc
Create Controllers¶
import { asyncHandler } from "../utils/AsyncHandler.js";
import { ApiResponse } from "../utils/ApiResponse.js";
import { ApiError } from "../utils/ApiError.js";
import { User } from "../models/user.model.js";
import { UnverifiedUser } from "../models/unverifiedUser.model.js";
import { generateJWTToken } from "../utils/GenerateToken.js";
import { uploadOnCloudinary } from "../config/cloudinary.js";
import { sendConfirmationMail } from "../utils/sendMail.js";
const registerUser = asyncHandler(async (req, res) => {
console.log("******** registerUser Function ********");
console.log("Request Body", req.body);
const { name, email, password } = req.body;
console.log("User details", name, email, password);
if (!name || !email || !password) {
throw new ApiError(400, "All fields are required");
}
const existingUser = await User.findOne({ email });
console.log("Existing User", existingUser);
if (existingUser) {
throw new ApiError(400, "User already exists");
}
const existingUnverifiedUser = await UnverifiedUser.findOne({ email });
console.log("Existing Unverified User", existingUnverifiedUser);
if (existingUnverifiedUser) {
throw new ApiError(400, "Already registered. Please verify your email");
}
const unverifiedUser = await UnverifiedUser.create({ name, email, password });
if (!unverifiedUser) {
throw new ApiError(500, "Failed to create User");
}
const confirmationMail = await sendConfirmationMail(email, unverifiedUser._id);
if (!confirmationMail) {
await UnverifiedUser.deleteOne({ _id: unverifiedUser._id });
throw new ApiError(500, "Failed to send confirmation mail");
}
return res.status(200).json(
new ApiResponse(
200,
{
name: unverifiedUser.name,
email: unverifiedUser.email,
},
"Please verify your email to continue"
)
);
});
const confirmEmail = asyncHandler(async (req, res) => {
const { id } = req.params;
if (!id) {
throw new ApiError(400, "Invalid request");
}
const unverifiedUser = await UnverifiedUser.findById(id);
if (!unverifiedUser) {
throw new ApiError(404, "User not found");
}
const user = await User.create({
name: unverifiedUser.name,
email: unverifiedUser.email,
password: unverifiedUser.password,
});
if (!user) {
throw new ApiError(500, "Failed to create User");
}
await UnverifiedUser.deleteOne({ _id: unverifiedUser._id });
return res.status(200).send("Email confirmed. You can now login");
});
const loginUser = asyncHandler(async (req, res) => {
console.log("******** loginUser Function ********");
const { email, password } = req.body;
if (!email || !password) {
throw new ApiError(400, "All fields are required");
}
console.log("User details", email, password);
const user = await User.findOne({ email });
if (user && (await user.matchPassword(password))) {
return res.status(200).json(
new ApiResponse(
200,
{
_id: user._id,
name: user.name,
email: user.email,
token: generateJWTToken(user._id),
},
"User logged in successfully"
)
);
}
throw new ApiError(401, "Invalid email or password");
});
export { uploadPicOnCloudinary, registerUser, confirmEmail, loginUser };
Create generate JWT token function¶
[[Generate JWT Token]]
Create verifyJWT middleware¶
import { User } from "../models/user.model.js";
import { ApiError } from "../utils/ApiError.js";
import { asyncHandler } from "../utils/asyncHandler.js";
import jwt from "jsonwebtoken";
export const verifyJWT = asyncHandler(async (req, res, next) => {
try {
const token = req.cookies?.accessToken || req.header("Authorization")?.replace("Bearer ", "");
if (!token) {
throw new ApiError(401, "Unauthorized request");
}
const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findById(decodedToken?._id).select("-password");
if (!user) {
throw new ApiError(401, "Invalid JWT Token");
}
req.user = user;
next();
} catch (error) {
throw new ApiError(401, error?.message || "Invalid JWT Token");
}
});