Menu
CoddyTech

Checking a Password

Part of the Auth and Security section of Coddy's Node.js journey. Lesson 2 of 17.

A hash cannot be reversed, so a login never reads the stored password back. You hash the attempt the same way and compare the two keys. Same way means the same salt: split the stored salt:hash and reuse its salt.

Compare with timingSafeEqual, not ===. === stops at the first byte that differs, so an attacker who times many answers learns how much of a guess was right. timingSafeEqual always takes the same time. It compares two Buffers of the same length and throws when the lengths differ.

import { timingSafeEqual } from 'node:crypto';

const expected = Buffer.from(process.env.API_KEY);
const given = Buffer.from(req.get('x-api-key') ?? '');
const ok = given.length === expected.length && timingSafeEqual(given, expected);

Buffer.from(hex, 'hex') turns hex text back into bytes.

challenge icon

Challenge

Easy
  • In passwords.js, add and export verifyPassword(password, stored): true when the password made that stored value.
  • In server.js, add POST /login with { username, password }: 200 { username }, or 401 { "error": "Wrong username or password" } for a wrong password or an unknown name.

Sign up ada, log in, then log in with a wrong password.

Try it yourself

import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';

const scryptAsync = promisify(scrypt);

// Turns a password into the text signup stores.
export async function hashPassword(password) {
    const salt = randomBytes(16).toString('hex');
    const key = await scryptAsync(password, salt, 64);
    return `${salt}:${key.toString('hex')}`;
}

All lessons in Auth and Security