Learn

Today we’ll be looking at how to protect and hash passwords through bcrypt without the use of a database.

When creating an authentication flow, we should never store passwords as plaintext. Instead, we can take the password retrieved from a user’s input and hash it using bcrypt. Once it’s hashed, then we can store it in our database.

A typical POST request for registering a user might look something like this:

app.post("/register", (req, res) => { const { email, password } = req.body; // Create a new user object to store in the database: user = new User({ email, password }); // Save user in database: await user.save(); res.redirect("login"); });

In the above example, passwords are not being hashed and are therefore stored as plaintext in the database.

Before creating a new user object, we must first hash the password and store that value:

const salt = await bcrypt.genSalt(10); const hash = await bcrypt.hash(password, salt); const newUser = { email, password: hash }; await user.save();

Once hashed, that value will be stored in our database and protect the password from brute-force attacks.

In order to log that registered user back in, a request without hashed passwords might look something like this:

app.post("/login", (req, res) => { const { email, password } = req.body; let user = await User.findOne({ email: email }); // If passwords don't match, redirect client back to the login page: if (user.password !== password) return res.redirect("login"); // If passwords match, redirect client along with the user object: res.render("profile", { user }); });

The issue above is, once again, plaintext passwords are being compared. Instead, bcrypt should be used to hash the user’s password input and compare it to the hash stored in the database:

const { email, password } = req.body; let user = await User.findOne({ email: email }); // ... // Use bcrypt to hash the retrieved password and compare it to hash stored in database: const matchedPassword = await bcrypt.compare(password, user.password);

Using bcrypt.compare() pulls the salt out of stored hash in the database and uses it to hash the retrieved password and perform the comparison. The function will then return true if the passwords match and false if they don’t.

With that in place, we have safely secured the endpoints in order to protect our user’s passwords when registering and logging in!

We have provided you with a basic application in order to register and log in users. Since we’re not using a database, we’re manually updating a JSON file and adding a new user whenever someone registers. Feel free to explore the app further before starting the exercises in order to get a better understanding of how it works.

Instructions

1.

In the users.routes.js file you’ll find a POST request to register new users. The flow is almost complete but the passwords still need to be hashed before storing them in the local database.

Add the missing code in order to generate a salt using 10 salt rounds, and store the value in a const variable called salt.

2.

Now that a salt has been generated, use it in order to hash the retrieved password.

Store the value in a const variable called hashedPassword.

3.

Under the POST request to log in a user, app.post("/login"), the password input must be compared to the hashed password in the database.

Use bcrypt to compare the user’s input password and the stored hashed password.

Store the value in a const variable called matchedPassword.

4.

Within the mini-browser, navigate to /users/register and attempt to register a new user.

If successful, try to log in with the same credentials.

Take this course for free

By signing up for Codecademy, you agree to Codecademy's Terms of Service & Privacy Policy.
Already have an account?