Start learning free

LESSON 166 OF 173 · BACKEND: BACKEND WITH AI

The AI Stored Passwords in TypeScript

Practice

An AI assistant wrote the shop's sign-up route. It answers 201 and looks fine, but look at what it saves:

app.post("/signup", (req: Request, res: Response) => {
  const data = req.body;
  const result = db.prepare("INSERT INTO users (email, password_hash) VALUES (?, ?)").run(data.email, data.password);
  res.status(201).json({ id: result.lastInsertRowid, email: data.email });
});

The column is called password_hash, but it holds the password itself. Anyone who sees the database (a backup, a leak) reads every password, and people reuse passwords on other sites. It also breaks the login: the shop's /login route, already written for you, checks passwords with checkPassword, which expects a hash. With the AI's sign-up, every login answers 401.

A hash is a one-way scramble: the password gives the hash, but the hash never gives the password back. hashPassword(password: string): string, a function already written at the top of the file, mixes in a random salt first, so two people with the same password get different hashes. checkPassword(passwordHash: string, password: string): boolean, right below it, tells you whether a password fits a saved hash:

const stored = hashPassword("open sesame");          // a string
console.log(stored.slice(0, 17));                   // scrypt:32768:8:1$
console.log(checkPassword(stored, "open sesame"));  // true
console.log(checkPassword(stored, "Open sesame"));  // false

The requests and the answers your app must give. GET /check/users is a checking route the course adds: it shows the users table with each salt and hash replaced by a label like <salt 1>.

POST /signup  {"email": "ana@example.com", "password": "secret123"}  →  201  {"email": "ana@example.com", "id": 1}
POST /signup  {"email": "ben@example.com", "password": "secret123"}  →  201  {"email": "ben@example.com", "id": 2}
GET /check/users  →  200  [{"email": "ana@example.com", "id": 1, "password_hash": "scrypt:32768:8:1$<salt 1>$<hash 1>"},
                           {"email": "ben@example.com", "id": 2, "password_hash": "scrypt:32768:8:1$<salt 2>$<hash 2>"}]
POST /login  {"email": "ana@example.com", "password": "secret123"}  →  200  {"email": "ana@example.com", "id": 1}
POST /login  {"email": "ana@example.com", "password": "Secret123"}  →  401  {"error": "Wrong email or password"}
POST /login  {"email": "ben@example.com", "password": "secret123"}  →  200  {"email": "ben@example.com", "id": 2}

Your task: rewrite the function of the /signup route. Save the email and hashPassword of the password, never the password itself, and answer 201 with the new user's id and email.


Assignment
Follow the Coding Tutorial to rewrite the /signup route so it stores a salted hash instead of the password.


Hint
The /login route is already correct: it only needs a real hash in the column. hashPassword is already in the file, near the top, and its return type tells TypeScript that the hash is a string. Keep both the password and the hash out of the answer.


STEP 1 OF 4
    Ctrl + Enter to check

    Ai Password Plain in TypeScript

    Keep going with TypeScript1,600+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free