Bird
Raised Fist0
Expressframework~10 mins

Password hashing with bcrypt in Express - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Password hashing with bcrypt
Receive plain password
Generate salt with bcrypt
Hash password + salt
Store hashed password
Later: Receive login password
Compare login password with stored hash
Return match result: true/false
This flow shows how bcrypt creates a salt, hashes a password, stores it, and later compares login attempts securely.
Execution Sample
Express
import bcrypt from 'bcrypt';

const password = 'mySecret123';
const saltRounds = 10;

async function hashPassword() {
  const salt = await bcrypt.genSalt(saltRounds);
  const hashed = await bcrypt.hash(password, salt);
  return hashed;
}

async function checkPassword(hashedPassword, inputPassword) {
  const match = await bcrypt.compare(inputPassword, hashedPassword);
  return match;
}
This code hashes a password with bcrypt and then checks if a login password matches the stored hash.
Execution Table
StepActionInputOutputNotes
1Receive plain passwordmySecret123mySecret123User inputs password
2Generate saltsaltRounds=10$2b$10$eW5...Salt created with cost factor 10
3Hash password + saltpassword + salt$2b$10$eW5...hashedvaluePassword hashed securely
4Store hashed password$2b$10$eW5...hashedvalueStored in DBHash saved, not plain password
5Receive login passwordmySecret123mySecret123User tries to login
6Compare login password with stored hashmySecret123, $2b$10$eW5...hashedvaluetruePassword matches hash
7Return match resulttrueAllow loginUser authenticated successfully
💡 Comparison returns false if passwords don't match, stopping login.
Variable Tracker
VariableStartAfter Step 2After Step 3After Step 4After Step 6
passwordundefinedmySecret123mySecret123mySecret123mySecret123
saltundefined$2b$10$eW5...$2b$10$eW5...$2b$10$eW5...$2b$10$eW5...
hashedundefinedundefined$2b$10$eW5...hashedvalue$2b$10$eW5...hashedvalue$2b$10$eW5...hashedvalue
matchundefinedundefinedundefinedundefinedtrue
Key Moments - 3 Insights
Why do we generate a salt before hashing the password?
The salt adds randomness to the password hash, making it unique even if two users have the same password. See Step 2 in the execution_table where salt is generated before hashing.
Why can't we just store the plain password instead of the hash?
Storing plain passwords is unsafe because if the database leaks, attackers get all passwords. Hashing protects passwords by storing only the hashed version (Step 4).
How does bcrypt verify the password without storing the plain password?
bcrypt compares the login password by hashing it with the stored salt inside the hash and checks if it matches the stored hash (Step 6).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the output of Step 3?
AA plain password string
BA salt string
CA hashed password string
DA boolean true/false
💡 Hint
Check the Output column at Step 3 in the execution_table.
At which step does the system decide if the login password matches the stored hash?
AStep 4
BStep 6
CStep 2
DStep 7
💡 Hint
Look for the step where bcrypt.compare is used in the execution_table.
If the saltRounds value is increased, what changes in the execution_table?
AStep 2 output salt will be longer and hashing slower
BStep 3 output will be plain password
CStep 6 match will always be false
DStep 7 will skip login
💡 Hint
Salt generation depends on saltRounds as shown in Step 2.
Concept Snapshot
Password hashing with bcrypt:
- Generate a salt with cost factor (saltRounds)
- Hash password + salt to create secure hash
- Store only the hash, never plain password
- On login, compare input password with stored hash
- bcrypt handles salt internally during compare
- Higher saltRounds means stronger but slower hashing
Full Transcript
This visual trace shows how bcrypt hashes passwords in an Express app. First, the plain password is received. Then bcrypt generates a salt using a cost factor called saltRounds. The password is combined with this salt and hashed securely. The hashed password is stored in the database, never the plain password. Later, when a user logs in, bcrypt compares the entered password with the stored hash by hashing it internally with the salt. If they match, login is allowed. This process protects user passwords by making it very hard for attackers to reverse the hash. Increasing saltRounds makes hashing stronger but slower.

Practice

(1/5)
1. What is the main purpose of using bcrypt in an Express app?
easy
A. To securely hash user passwords before saving them
B. To speed up server response time
C. To format JSON data
D. To manage user sessions

Solution

  1. Step 1: Understand bcrypt's role

    Bcrypt is a library designed to hash passwords securely, making them hard to read if stolen.
  2. Step 2: Identify the correct purpose in Express

    In Express apps, bcrypt is used to hash passwords before storing them in a database to protect user data.
  3. Final Answer:

    To securely hash user passwords before saving them -> Option A
  4. Quick Check:

    Password hashing = Secure storage [OK]
Hint: Bcrypt is for password security, not speed or formatting [OK]
Common Mistakes:
  • Thinking bcrypt speeds up server
  • Confusing bcrypt with session management
  • Using bcrypt for data formatting
2. Which of the following is the correct way to hash a password asynchronously using bcrypt in Express?
easy
A. const hashed = bcrypt.hashSync(password, 10);
B. const hashed = bcrypt.hash(password);
C. const hashed = await bcrypt.hash(password, 10);
D. const hashed = bcrypt.compare(password, 10);

Solution

  1. Step 1: Identify asynchronous bcrypt hashing syntax

    Bcrypt's async hash function requires await and two arguments: the password and salt rounds.
  2. Step 2: Check each option

    const hashed = await bcrypt.hash(password, 10); uses await bcrypt.hash(password, 10); which is correct async usage. const hashed = bcrypt.hashSync(password, 10); is synchronous, C is wrong function, B misses salt rounds.
  3. Final Answer:

    const hashed = await bcrypt.hash(password, 10); -> Option C
  4. Quick Check:

    Async hash needs await and salt rounds [OK]
Hint: Async bcrypt hash always uses await and salt rounds [OK]
Common Mistakes:
  • Using synchronous hashSync instead of async
  • Calling compare instead of hash
  • Omitting salt rounds argument
3. What will be the output of this code snippet?
const bcrypt = require('bcrypt');
async function test() {
  const password = 'secret123';
  const hash = await bcrypt.hash(password, 5);
  const match = await bcrypt.compare('secret123', hash);
  console.log(match);
}
test();
medium
A. Error
B. false
C. undefined
D. true

Solution

  1. Step 1: Understand bcrypt.hash and bcrypt.compare

    The code hashes 'secret123' with salt rounds 5, then compares the original password to the hash.
  2. Step 2: Analyze the compare result

    Since the password matches the hash, bcrypt.compare returns true, which is logged.
  3. Final Answer:

    true -> Option D
  4. Quick Check:

    Password matches hash = true [OK]
Hint: Compare returns true if password matches hash [OK]
Common Mistakes:
  • Expecting false because of low salt rounds
  • Thinking compare returns the hash
  • Missing await causing undefined
4. Identify the error in this Express route using bcrypt:
app.post('/signup', async (req, res) => {
  const { password } = req.body;
  const hashed = bcrypt.hash(password, 10);
  // Save hashed password to DB
  res.send('User created');
});
medium
A. bcrypt.hash requires 3 arguments, only 2 given
B. Missing await before bcrypt.hash causing a Promise instead of hash
C. bcrypt.hashSync should be used instead of bcrypt.hash
D. Password should not be hashed before saving

Solution

  1. Step 1: Check bcrypt.hash usage

    Bcrypt.hash is async and returns a Promise, so it needs await to get the hashed string.
  2. Step 2: Identify missing await effect

    Without await, hashed is a Promise, not the actual hash, causing errors when saving.
  3. Final Answer:

    Missing await before bcrypt.hash causing a Promise instead of hash -> Option B
  4. Quick Check:

    Async bcrypt.hash needs await [OK]
Hint: Always await async bcrypt.hash to get the hash string [OK]
Common Mistakes:
  • Forgetting await on async bcrypt.hash
  • Using wrong number of arguments
  • Thinking hashSync is mandatory
5. You want to create a secure signup route in Express that hashes the password and then verifies it immediately to confirm hashing worked. Which code snippet correctly does this?
hard
A. app.post('/signup', async (req, res) => { const { password } = req.body; const hash = await bcrypt.hash(password, 12); const valid = await bcrypt.compare(password, hash); if (valid) res.send('Signup successful'); else res.status(500).send('Hashing error'); });
B. app.post('/signup', (req, res) => { const { password } = req.body; const hash = bcrypt.hashSync(password, 12); const valid = bcrypt.compareSync(password, hash); if (valid) res.send('Signup successful'); else res.status(500).send('Hashing error'); });
C. app.post('/signup', async (req, res) => { const { password } = req.body; const hash = bcrypt.hash(password, 12); const valid = bcrypt.compare(password, hash); if (valid) res.send('Signup successful'); else res.status(500).send('Hashing error'); });
D. app.post('/signup', async (req, res) => { const { password } = req.body; const hash = await bcrypt.hash(password); const valid = await bcrypt.compare(password, hash); if (valid) res.send('Signup successful'); else res.status(500).send('Hashing error'); });

Solution

  1. Step 1: Check async usage and salt rounds

    app.post('/signup', async (req, res) => { const { password } = req.body; const hash = await bcrypt.hash(password, 12); const valid = await bcrypt.compare(password, hash); if (valid) res.send('Signup successful'); else res.status(500).send('Hashing error'); }); uses async/await correctly and provides salt rounds (12) to bcrypt.hash, which is best practice.
  2. Step 2: Verify immediate password check

    It compares the original password with the hash using await bcrypt.compare, then sends success if valid.
  3. Step 3: Analyze other options

    app.post('/signup', (req, res) => { const { password } = req.body; const hash = bcrypt.hashSync(password, 12); const valid = bcrypt.compareSync(password, hash); if (valid) res.send('Signup successful'); else res.status(500).send('Hashing error'); }); uses sync methods which block the server, C misses await causing Promises, D misses salt rounds in hash.
  4. Final Answer:

    Option A code snippet with async/await and salt rounds -> Option A
  5. Quick Check:

    Async hash with salt rounds + compare = correct [OK]
Hint: Use async/await with salt rounds and compare for secure signup [OK]
Common Mistakes:
  • Using synchronous bcrypt methods in async routes
  • Forgetting await causing Promises
  • Omitting salt rounds in hash