basicaly i am writing code setup here only for me. Because i am facing lots of dificulty in development and geting a good job
This setup i usfe in code
Dependencies
- bcrypt It helps us hash passwords before saving them in the database, ensuring they are stored securely in an encrypted format. How to use: const hashedPassword = await bcrypt.hash(password, salt); you can verify the hashed password using bcrypt.compare(password,user.password).
- cookie-parser It helps us parse cookies from incoming requests and manage tokens within cookies. By using cookies, we can maintain user sessions securely and persist login states across requests.
- cors It enables Cross-Origin Resource Sharing (CORS), allowing the backend to accept requests from the frontend hosted on a different domain or port. Useful when connecting a React/Angular/Vue frontend to a Node.js backend.
- dotenv It allows us to load environment variables from a .env file into process.env. This is essential for securing sensitive information like database connection strings, secret keys, and API credentials.
- mongoose It is an Object Data Modeling (ODM) library for MongoDB and Node.js. It provides schema-based solutions to model application data and includes built-in validation. Example: const mongoose = require('mongoose'); mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
- nodemailer With the help of Nodemailer, we can send emails to users. This is often used for sending verification emails, password reset links, or notifications.
- nodemon It helps keep the server running continuously and monitors file changes in the project. Whenever a file changes, it automatically restarts the server, saving development time. Install and run it using:
- passport Passport is an authentication middleware for Node.js. It provides strategies for handling various authentication mechanisms like local authentication, OAuth, Google, Facebook, etc.
- passport-jwt It is a Passport strategy for securing APIs using JSON Web Tokens (JWT). This ensures secure user authentication by validating the token sent in the request headers. Example usage involves extracting the token from cookies or headers and verifying it.
This is header
import UserModel from "../model/User.js";
import bcrypt from 'bcrypt';
import dotenv from 'dotenv';
import sendEmailVerificationByOTP from "../utils/sendEmailVerificationByOTP.js";
import EmailVerificationModel from "../model/EmailVerificaion.js";
import transporter from "../config/emailConfig.js";
import jwt from "jsonwebtoken"
dotenv.config();
Signup user
const signup = async (req, res) => {
try {
const { name, email, password } = req.body;
// all field is require
if (!name || !email || !password ){
return res.status(400).json({ status: "failed", message: "All fields are required" })
}
// user already exist
const existingUser = await UserModel.findOne({ email });
if (existingUser) {
return res.status(400).json({ status: "Fail", message: "User already exist" })
}
// salt
const salt = await bcrypt.genSalt(Number(process.env.SALT));
// hasspassword
const hasspassword = await bcrypt.hash(password, salt)
const newUser = await new UserModel({
name,
email,
password: hasspassword
}).save();
//CALL send otp to user (This function is written in utils folder)
sendEmailVerificationByOTP(req, newUser)
res.status(200).json({
status: "sucess",
message: "your accoount is sucessfuly created",
user: { id: newUser._id, email: newUser.email }
})
} catch (error) {
console.error(error)
return res.status(400).json({ status: "failed", message: "Unable to Register, please try again later" })
}
}
Verify email
const verifyEmail = async (req, res) => {
try {
const { email, otp } = req.body;
// Check if all required fields are provided
if (!email || !otp) {
return res.status(400).json({ status: "failed", message: "All fields are required" });
}
// Check if the email exists
const userEmail = await UserModel.findOne({ email });
if (!userEmail) {
return res.status(400).json({ status: "failed", message: "Email does not exist" });
}
// Check if the email is already verified
if (userEmail.is_verified) {
return res.status(400).json({ status: "failed", message: "This email is already verified" });
}
// Check if there is a matching email verification OTP
const emailVerification = await EmailVerificationModel.findOne({ userId: userEmail._id, otp });
if (!emailVerification) {
// Resend OTP if not verified
await sendEmailVerificationByOTP(req, userEmail);
return res.status(400).json({ status: "failed", message: "Invalid OTP. A new OTP has been sent to your email." });
}
// Check if OTP is expired
const currentTime = new Date();
const expirationTime = new Date(emailVerification.createdAt.getTime() + 15 * 60 * 1000); // 15 minutes
if (currentTime > expirationTime) {
// OTP expired, send new OTP
await sendEmailVerificationByOTP(req, userEmail);
return res.status(400).json({ status: "failed", message: "OTP expired. A new OTP has been sent to your email." });
}
// Mark the user's email as verified
userEmail.is_verified = true;
await userEmail.save();
// Remove all OTP entries for the user
await EmailVerificationModel.deleteMany({ userId: userEmail._id });
return res.status(200).json({ status: "success", message: "Email verified successfully" });
} catch (error) {
console.error(error);
return res.status(500).json({ status: "failed", message: "An error occurred while verifying the email." });
}
};
User Login
const Login = async (req, res) => {
try {
const { email, password } = req.body
// All field is require
if (!email || !password) {
return res.status(400).json({ status: "fail to login", message: "All field is required" })
}
// Email is exist or not
const user = await UserModel.findOne({ email })
if (!user) {
return res.status(400).json({ status: "Fail to login", message: "Email or password is not exist" })
}
// is user is verified or not
if (!user.is_verified) {
return res.status(400).json({ status: "fail to login", message: "Account is not active" })
}
// Check the user password is match or not
const isMatch = await bcrypt.compare(password, user.password)
//if password is not match
if (!isMatch) {
return res.status(400).json({ status: "Fail to login", message: "password is not same" })
}
// Generate single long-lived token (30 days)
console.log("JWT Secret Key:", process.env.JWT_SECRET_KEY);
const tokenExp = Math.floor(Date.now() / 1000) + (30 * 24 * 60 * 60);
const token = jwt.sign(
{
id: user._id,
roles: user.role[0],
exp: tokenExp
},
process.env.JWT_SECRET_KEY
);
// Send response
res.status(200).json({
user: { id: user._id, email: user.email, name: user.name, roles: user.role[0] },
status: "success",
message: "Login successful",
token,
token_exp: tokenExp,
is_auth: true
});
} catch (error) {
console.log(error)
res.status(400).json({ status: "Fail to login", message: "" })
}
}
Profile
const userProfile = async (req, res) => {
res.send({ "user": req.user })
}
Change Password
const changePassword = async (req, res) => {
try {
const { password, confirm_password } = req.body
if (!password || !confirm_password) {
res.status(400).json({ statu: "Fail", message: "all filed is require" })
}
if (password !== confirm_password) {
res.statu(400).json({ status: "Fail", message: "Password is not match" })
}
const salt = await bcrypt.genSalt(Number(process.env.SALT))
const hashPassword = await bcrypt.hash(password, salt)
await UserModel.findByIdAndUpdate(req.user._id, { $set: { password: hashPassword } })
// Send success response
res.status(200).json({ status: "success", message: "Password changed successfully" });
} catch (error) {
console.error(error);
res.status(500).json({ status: "failed", message: "Unable to change password, please try again later" });
}
}
Send Password Reset Link via Email
const sendUserPasswordResetEmail = async (req, res) => {
try {
// Extract email from req.body
const { email } = req.body;
// Check if email is provided
if (!email) {
return res.status(400).json({ status: "failed", message: "Email field is required" });
}
// Find user by email
const user = await UserModel.findOne({ email: email });
if (!user) {
return res.status(404).json({ status: "failed", message: "Email doesn't exist" });
}
// Create a secret and token for password reset
const secret = user._id + process.env.JWT_ACCESS_TOKEN_SECRET_KEY;
const token = jwt.sign({ userId: user._id }, secret, { expiresIn: '15m' });
// Construct the reset password link
const resetLink = `${process.env.FRONTEND_HOST}/account/reset-password-confirm/${user._id}/${token}`;
console.log(resetLink)
// Send password reset email
await transporter.sendMail({
from: process.env.EMAIL_FROM,
to: user.email,
subject: "Reset your password",
html: `<p>Hello ${user.name},</p><p>Please <a href="${resetLink}">click here</a> to reset your password.</p>`,
});
// Respond with success
res.status(200).json({ status: "success", message: "Password reset email sent. Please check your email." });
} catch (error) {
console.error(error);
res.status(500).json({ status: "failed", message: "Unable to send password reset email. Please try again later." });
}
};
Reset password
const resetPassword = async (req, res) => {
try {
const { password, confirm_password } = req.body;
const { id, token } = req.params;
// Find user by ID
const user = await UserModel.findById(id);
if (!user) {
return res.status(404).json({ status: "failed", message: "User not found" });
}
// Validate token
const new_secret = user._id + process.env.JWT_ACCESS_TOKEN_SECRET_KEY;
jwt.verify(token, new_secret);
// Check if password and password_confirmation are provided
if (!password || !confirm_password) {
return res.status(400).json({ status: "failed", message: "New Password and Confirm New Password are required" });
}
// Check if password and password_confirmation match
if (password !== confirm_password) {
return res.status(400).json({ status: "failed", message: "New Password and Confirm New Password don't match" });
}
// Generate salt and hash new password
const salt = await bcrypt.genSalt(10);
const newHashPassword = await bcrypt.hash(password, salt);
// Update user's password
await UserModel.findByIdAndUpdate(user._id, { $set: { password: newHashPassword } });
// Send success response
res.status(200).json({ status: "success", message: "Password reset successfully" });
} catch (error) {
console.log(error);
if (error.name === "TokenExpiredError") {
return res.status(400).json({ status: "failed", message: "Token expired. Please request a new password reset link." });
}
return res.status(500).json({ status: "failed", message: "Unable to reset password. Please try again later." });
}
}
Top comments (0)