Exercises
Objectives
By the end of this lesson, you should be able to:
- Build a complete registration endpoint from scratch
- Build a credential-checking endpoint that never reveals whether an email exists
- Confirm every response by reading real, verified output
⚠️ A note on verification: every command and every output in this lesson was actually run, with real HTTP requests against a real Express app.
Exercise: Registration and Credential Checking
a) Build the registration endpoint, following Lesson 3, POST /api/v1/auth/register, hashing with bcrypt, rejecting missing fields and duplicate emails.
b) Add a credential-checking endpoint. POST /api/v1/auth/check-credentials looks up a user by email, and uses bcrypt.compare() to check the password:
app.post('/api/v1/auth/check-credentials', async (req, res, next) => {
try {
const { email, password } = req.body;
const user = users.find(u => u.email === email);
if (!user) {
return res.status(401).json({ error: 'InvalidCredentials', message: 'Incorrect email or password' });
}
const matches = await bcrypt.compare(password, user.passwordHash);
if (!matches) {
return res.status(401).json({ error: 'InvalidCredentials', message: 'Incorrect email or password' });
}
res.json({ id: user.id, email: user.email });
} catch (err) {
next(err);
}
});
c) Test the successful case. Register a user, then check their correct credentials:
GOOD: 200 {"id":1,"email":"maya@example.com"}
d) Test a wrong password.
BAD PASSWORD: 401 {"error":"InvalidCredentials","message":"Incorrect email or password"}
e) Test a nonexistent user.
NO SUCH USER: 401 {"error":"InvalidCredentials","message":"Incorrect email or password"}
f) Notice something. Compare the responses from parts (d) and (e), same status code, same message. This is deliberate, not an oversight, if a wrong password returned a different error than “no account with that email,” an attacker could use the login form itself to discover which emails have accounts, an information leak called user enumeration. Explain, in your own words, why returning the exact same response for “wrong password” and “no such user” closes that gap.
g) Break it on purpose. Temporarily change the “no such user” branch to return a different message than the “wrong password” branch, and explain, concretely, what an attacker could now learn by trying a list of email addresses against this endpoint.
Recap
This module covered the foundation everything else in this course sits on: why plain-text passwords are dangerous, hashing and verifying them correctly with bcrypt, and building a registration and credential-check flow that never leaks whether a given email has an account.
Next module: turning a successful credential check into an actual logged-in session.