How to Implement password reset via email in node.js ?

Hi guys today we gonna implement password reset via email in node.js. If you user forgot there password, we send an link to you user email account. From that link user can add there new password. If you just wanna know how this concept works, you can s…


This content originally appeared on DEV Community and was authored by Jahangeer

Hi guys today we gonna implement password reset via email in node.js. If you user forgot there password, we send an link to you user email account. From that link user can add there new password. If you just wanna know how this concept works, you can start from Model section .

So let's start coding...

Demo Video

Project Github Link

App Overview :
Project Structure
project_structure
Following table shows the overview of Rest APIs that exported

Methods Urls Actions
POST /users create user
POST /password-reset Send password reset link
POST /password-reset/:userId/:token Reset user password

create Node.js App

$ mkdir node-email-password-reset
$ cd node-email-password-reset
$ npm init --yes
$ npm install express mongoose dotenv nodemailer joi

Express : Express is minimal and flexible Node.js web applicaton framework.
Mongoose : Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js.
Nodemailer : Nodemailer allow us to send email.
Joi : Joi is an object schema description language and validator for javascript objects.
Dotenv : It loads environment variables from a .env file.

package.json

{
  "name": "node-email-password-reset",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dotenv": "^9.0.2",
    "express": "^4.17.1",
    "joi": "^17.4.0",
    "mongoose": "^5.12.10",
    "nodemailer": "^6.6.0"
  }
}

Setup Express Web Server
In the root folder, let's create index.js file :

require("dotenv").config();
const express = require("express");
const app = express();

app.use(express.json());

const port = process.env.PORT || 8080;
app.listen(port, () => console.log(`Listening on port ${port}...`));

Configure Environment Variables
In the root folder, let's create .env file :

DB = // mongodb url
HOST = // email host
USER = // email id
PASS = // email password
SERVICE = // email service
BASE_URL = "http://localhost:8080/api"

Configure MongoDB Database
In the root folder, let's create db.js file :

const mongoose = require("mongoose");

module.exports = connection = async () => {
    try {
        const connectionParams = {
            useNewUrlParser: true,
            useCreateIndex: true,
            useUnifiedTopology: true,
        };
        await mongoose.connect(process.env.DB, connectionParams);
        console.log("connected to database.");
    } catch (error) {
        console.log(error, "could not connect database.");
    }
};

import db.js in index.js and call it :

//....
const connection = require("./db");
const express = require("express");
const app = express();

connection();

app.use(express.json());
//....

Define The Models
In the root directory create models folder.
models/user.js like this :

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const Joi = require("joi");

const userSchema = new Schema({
    name: {
        type: String,
        required: true,
    },
    email: {
        type: String,
        required: true,
    },
    password: {
        type: String,
        required: true,
    },
});

const User = mongoose.model("user", userSchema);

const validate = (user) => {
    const schema = Joi.object({
        name: Joi.string().required(),
        email: Joi.string().email().required(),
        password: Joi.string().required(),
    });
    return schema.validate(user);
};

module.exports = { User, validate };

models/token.js file like this :

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const tokenSchema = new Schema({
    userId: {
        type: Schema.Types.ObjectId,
        required: true,
        ref: "user",
    },
    token: {
        type: String,
        required: true,
    },
    createdAt: {
        type: Date,
        default: Date.now,
        expires: 3600,
    },
});

module.exports = mongoose.model("token", tokenSchema);

Configure The Email Transporter
In the root directory create utils folder.
utils/sendEmail.js file like this :

const nodemailer = require("nodemailer");

const sendEmail = async (email, subject, text) => {
    try {
        const transporter = nodemailer.createTransport({
            host: process.env.HOST,
            service: process.env.SERVICE,
            port: 587,
            secure: true,
            auth: {
                user: process.env.USER,
                pass: process.env.PASS,
            },
        });

        await transporter.sendMail({
            from: process.env.USER,
            to: email,
            subject: subject,
            text: text,
        });

        console.log("email sent sucessfully");
    } catch (error) {
        console.log(error, "email not sent");
    }
};

module.exports = sendEmail;

Define The Routes
In the root directory create routes folder.
routes/users.js file like this :

const { User, validate } = require("../models/user");
const express = require("express");
const router = express.Router();

router.post("/", async (req, res) => {
    try {
        const { error } = validate(req.body);
        if (error) return res.status(400).send(error.details[0].message);

        const user = await new User(req.body).save();

        res.send(user);
    } catch (error) {
        res.send("An error occured");
        console.log(error);
    }
});

module.exports = router;

routes/passwordReset.js file like this :

const { User } = require("../models/user");
const Token = require("../models/token");
const sendEmail = require("../utils/sendEmail");
const crypto = require("crypto");
const Joi = require("joi");
const express = require("express");
const router = express.Router();

router.post("/", async (req, res) => {
    try {
        const schema = Joi.object({ email: Joi.string().email().required() });
        const { error } = schema.validate(req.body);
        if (error) return res.status(400).send(error.details[0].message);

        const user = await User.findOne({ email: req.body.email });
        if (!user)
            return res.status(400).send("user with given email doesn't exist");

        let token = await Token.findOne({ userId: user._id });
        if (!token) {
            token = await new Token({
                userId: user._id,
                token: crypto.randomBytes(32).toString("hex"),
            }).save();
        }

        const link = `${process.env.BASE_URL}/password-reset/${user._id}/${token.token}`;
        await sendEmail(user.email, "Password reset", link);

        res.send("password reset link sent to your email account");
    } catch (error) {
        res.send("An error occured");
        console.log(error);
    }
});

router.post("/:userId/:token", async (req, res) => {
    try {
        const schema = Joi.object({ password: Joi.string().required() });
        const { error } = schema.validate(req.body);
        if (error) return res.status(400).send(error.details[0].message);

        const user = await User.findById(req.params.userId);
        if (!user) return res.status(400).send("invalid link or expired");

        const token = await Token.findOne({
            userId: user._id,
            token: req.params.token,
        });
        if (!token) return res.status(400).send("Invalid link or expired");

        user.password = req.body.password;
        await user.save();
        await token.delete();

        res.send("password reset sucessfully.");
    } catch (error) {
        res.send("An error occured");
        console.log(error);
    }
});

module.exports = router;

If you are using this routes in front-end, you might need another route in passwordReset.js. We need to show password reset form only if the link is valid. So, we need a GET route which will validate the link and show password reset form.

Import routes in index.js

//...
const passwordReset = require("./routes/passwordReset");
const users = require("./routes/users");
const connection = require("./db");
//.....

app.use(express.json());

app.use("/api/users", users);
app.use("/api/password-reset", passwordReset);
//....

That's it, test the APIs in postman, If you found any mistakes or making code better let me know in comment. For better understanding please watch Youtube video. Subscribe to my Youtube channel to get more knowledgeable content every week.

Arigato gozaimasu.. ?


This content originally appeared on DEV Community and was authored by Jahangeer


Print Share Comment Cite Upload Translate Updates
APA

Jahangeer | Sciencx (2021-05-23T10:21:08+00:00) How to Implement password reset via email in node.js ?. Retrieved from https://www.scien.cx/2021/05/23/how-to-implement-password-reset-via-email-in-node-js/

MLA
" » How to Implement password reset via email in node.js ?." Jahangeer | Sciencx - Sunday May 23, 2021, https://www.scien.cx/2021/05/23/how-to-implement-password-reset-via-email-in-node-js/
HARVARD
Jahangeer | Sciencx Sunday May 23, 2021 » How to Implement password reset via email in node.js ?., viewed ,<https://www.scien.cx/2021/05/23/how-to-implement-password-reset-via-email-in-node-js/>
VANCOUVER
Jahangeer | Sciencx - » How to Implement password reset via email in node.js ?. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/05/23/how-to-implement-password-reset-via-email-in-node-js/
CHICAGO
" » How to Implement password reset via email in node.js ?." Jahangeer | Sciencx - Accessed . https://www.scien.cx/2021/05/23/how-to-implement-password-reset-via-email-in-node-js/
IEEE
" » How to Implement password reset via email in node.js ?." Jahangeer | Sciencx [Online]. Available: https://www.scien.cx/2021/05/23/how-to-implement-password-reset-via-email-in-node-js/. [Accessed: ]
rf:citation
» How to Implement password reset via email in node.js ? | Jahangeer | Sciencx | https://www.scien.cx/2021/05/23/how-to-implement-password-reset-via-email-in-node-js/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.