DEV Community

Cover image for Day 37 of #100DaysOfCode — Authentication Part I: Hashing Passwords
M Saad Ahmad
M Saad Ahmad

Posted on

Day 37 of #100DaysOfCode — Authentication Part I: Hashing Passwords

When building authentication systems, one of the biggest security mistakes that can be made is storing passwords in plain text.

If your database ever gets leaked, every user’s password becomes instantly visible.

That’s why modern applications never store real passwords — they store hashed passwords.

For Day 37, the goal was to understand:

  • Why password hashing is important
  • What hashing actually means
  • What salting is
  • How to hash passwords using bcrypt
  • How login verification works
  • How to implement this in a Node.js + MongoDB backend

Why Password Hashing Is Important

A bad implementation looks like this:

{
  "email": "user@email.com",
  "password": "mypassword123"
}
Enter fullscreen mode Exit fullscreen mode

If the database is compromised, attackers can instantly see user passwords.

This becomes dangerous because:

  • Many users reuse passwords
  • Attackers can access other accounts (email, banking, social media)

The Correct Way: Store Hashed Passwords

A secure implementation stores a hashed version of the password:

{
  "email": "user@email.com",
  "password": "$2b$10$kjsdfhksjdfh..."
}
Enter fullscreen mode Exit fullscreen mode

Now even if the database leaks, the attacker cannot directly read the password.

Instead of the real password, they only see a hash.


What is Password Hashing?

Hashing converts a password into a random-looking string using a mathematical algorithm.

Example:

password123
Enter fullscreen mode Exit fullscreen mode

Becomes something like:

$2b$10$Fv5Qn2H...
Enter fullscreen mode Exit fullscreen mode

Important Properties of Hashing

Property Meaning
Deterministic The same input produces the same output (when using the same salt)
One-way The hash cannot be reversed back into the original password
Fixed length Hash outputs have a consistent structure

⚠️ Important clarification:

Hashing is not encryption.

  • Encryption → reversible
  • Hashing → one-way

🧂 What is Salting?

A salt is random data added to a password before hashing.

Example concept:

password + randomSalt → hash
Enter fullscreen mode Exit fullscreen mode

Why this matters:

Without salting, attackers can use rainbow tables (precomputed hash databases) to guess passwords quickly.

Salting ensures that:

  • The same password produces different hashes
  • Rainbow table attacks become ineffective

Good news:

Libraries like bcrypt automatically generate and store the salt.


Installing bcrypt (Node.js)

To hash passwords in a Node.js application, we commonly use bcrypt.

Install it using npm:

npm install bcrypt
Enter fullscreen mode Exit fullscreen mode

Then import it:

const bcrypt = require("bcrypt");
Enter fullscreen mode Exit fullscreen mode

Hashing Passwords During User Registration

When a user registers, we hash the password before storing it in the database.

Example inside a controller:

const bcrypt = require("bcrypt");

const hashedPassword = await bcrypt.hash(req.body.password, 10);
Enter fullscreen mode Exit fullscreen mode

What does 10 mean?

10 = salt rounds
Enter fullscreen mode Exit fullscreen mode

Salt rounds determine how many times the hashing algorithm runs.

Rounds Result
Lower Faster but less secure
Higher More secure but slower

Most applications use 10–12 rounds.


Saving the User in the Database

Example with MongoDB + Mongoose:

const user = await User.create({
  email: req.body.email,
  password: hashedPassword
});
Enter fullscreen mode Exit fullscreen mode

Now the database stores only the hashed password.


Comparing Passwords During Login

When a user logs in:

  1. The user enters a password
  2. The server compares it with the stored hash

Example:

const isMatch = await bcrypt.compare(
  req.body.password,
  user.password
);
Enter fullscreen mode Exit fullscreen mode

If the result is:

true
Enter fullscreen mode Exit fullscreen mode

The password is correct, and login can proceed.


Authentication Flow (High-Level)

Here is the simplified authentication flow:

User registers
      ↓
Password gets hashed
      ↓
Stored in the database
      ↓
User logs in
      ↓
Entered password compared with stored hash
      ↓
If match → authentication successful
Enter fullscreen mode Exit fullscreen mode

Example Mongoose User Schema

Your User model might look like this:

const userSchema = new mongoose.Schema({
  email: {
    type: String,
    required: true
  },
  password: {
    type: String,
    required: true
  }
});
Enter fullscreen mode Exit fullscreen mode

Important rule:

Passwords must always be stored in hashed form.

Never store plain-text passwords in a production application.


Key Takeaways

  • Never store passwords as plain text
  • Always hash passwords before saving them
  • bcrypt is one of the most widely used password hashing libraries
  • Salting protects against rainbow table attacks
  • Use bcrypt.compare() to verify login passwords

Thank you for reading. Feel free to share your thoughts!

Top comments (0)