DEV Community

Harendra
Harendra

Posted on

This is back end setup for app and web

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

  1. 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).
  2. 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.
  3. 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.
  4. 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.
  5. 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 });
  6. 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.
  7. 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:
  8. passport Passport is an authentication middleware for Node.js. It provides strategies for handling various authentication mechanisms like local authentication, OAuth, Google, Facebook, etc.
  9. 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();

Enter fullscreen mode Exit fullscreen mode

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" })
  }

}

Enter fullscreen mode Exit fullscreen mode

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." });
  }
};
Enter fullscreen mode Exit fullscreen mode

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: "" })
  }
}

Enter fullscreen mode Exit fullscreen mode

Profile

const userProfile = async (req, res) => {
  res.send({ "user": req.user })
}

Enter fullscreen mode Exit fullscreen mode

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" });
  }
}

Enter fullscreen mode Exit fullscreen mode

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." });
  }
};
Enter fullscreen mode Exit fullscreen mode

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." });
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)