Mastering Secure Password Flows with Node.js and MongoDB

By Ararat Tonoyan
Picture of the author
Published on
mastering-secure-password-with-node-js-and-mongoDB

Mastering Secure Password Flows with Node.js and MongoDB: When Security Becomes an Art!

Greetings, noble guardians of code!

If the thought of your user's password security gives you more chills than the ending of a thriller movie, then you've come to the right place! Sit back, grab your favorite fuel (caffeine is my bet), and let's together navigate the secure waters of password flows with Node.js and MongoDB.

Exciting journey ahead

Step 1: Picking Your Security Companion

In the vast universe of npm packages, choosing the right tool can feel like finding Waldo. Let me save you the hassle: bcrypt is your friend here!

npm install bcrypt

Step 2: Crafting the Perfect Hashed Password

Storing the actual password is as bad as leaving your front door wide open while you're away on vacation. Instead, we store a hashed version of it.

const bcrypt = require('bcrypt');
const saltRounds = 10; 

bcrypt.hash('top_secret_password', saltRounds, function(err, hash) {
  if(err) {
    console.log(err);
  }
  // Now go store this `hash` in MongoDB, you great developer you!
});

Step 3: Password Check with the Hash

Okay, now that we've got a safely hashed password, how do we check the entered password at login? bcrypt gives you a simple yet powerful method for this:

bcrypt.compare('entered_password', hash, function(err, result) {
  if(err) {
    console.log(err);
  }
  if (result) {
    // Hurray, passwords match! Welcome in!
  } else {
    // Alas, passwords don't match. Not today, sir!
  }
});

Step 4: MongoDB - The Trusty Sidekick

Now, what's a superhero without a sidekick? MongoDB, get in here! We need a place to store our hashed passwords, right? First, we need mongoose:

npm install mongoose

And then let's create a User schema:

const mongoose = require('mongoose');

const UserSchema = new mongoose.Schema({
  username: {
    type: String,
    required: true,
    unique: true
  },
  password: {
    type: String,
    required: true
  },
});

module.exports = mongoose.model('User', UserSchema);

Step 5: Tying Up The Package

Now for the grand finale, let's wrap it all together:

const express = require('express');
const app = express();
app.use(express.json());

// User registration
app.post('/register', async (req, res) => {
  try {
    const { username, password } = req.body;
    if(!username || !password) {
      return res.status(400).send("Invalid Input");
    }
    const userExists = await User.findOne({ username });
    if(userExists) {
      return res.status(400).send("User Already Exists");
    }
    const hashedPassword = await bcrypt.hash(password, saltRounds);
    const user = new User({ username, password: hashedPassword });


    await user.save();
    res.sendStatus(201);
  } catch(err) {
    console.log(err);
    res.sendStatus(500);
  }
});

// User login
app.post('/login', async (req, res) => {
  try {
    const { username, password } = req.body;
    if(!username || !password) {
      return res.status(400).send("Invalid Input");
    }
    const user = await User.findOne({ username });
    if(!user) {
      return res.status(400).send("User does not exist");
    }
    const valid = await bcrypt.compare(password, user.password);

    if (valid) {
      res.sendStatus(200);
    } else {
      res.sendStatus(403);
    }
  } catch(err) {
    console.log(err);
    res.sendStatus(500);
  }
});

Closing Thoughts

Remember, folks, when it comes to securing your user's passwords, it's not just about the destination, it's about the journey (and the salt rounds, and the hashed passwords). Let's ensure the safety of our users' data because nothing spoils a user's day more than a data breach!

Security is important

Happy coding!

Stay Tuned

Want to become a Solidity pro?
The best articles, links and news related to web development delivered once a week to your inbox.