From a183aca4d863c833f6ff1dc7ddbd54f12b67fcc1 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Thu, 16 Oct 2025 13:15:08 -0700 Subject: [PATCH] feat(auth): implement secure password authentication - Replace plaintext password comparison with bcrypt verification - Hash passwords before database storage in registration - Validate bcrypt hashes during login to reject legacy plaintext - Update password change and reset flows with proper hashing - Add legacy password detection for security enforcement --- services/auth/auth.service.ts | 43 +++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/services/auth/auth.service.ts b/services/auth/auth.service.ts index b7549e6..ce334b7 100644 --- a/services/auth/auth.service.ts +++ b/services/auth/auth.service.ts @@ -4,6 +4,7 @@ import { EmailVerificationService } from './emailVerification.service'; import { databaseService } from '../database'; import { logger } from '../logging'; import { tokenService } from './token.service'; +import { hashPassword, verifyPassword, isBcryptHash } from './password.service'; const emailVerificationService = new EmailVerificationService(); @@ -22,9 +23,11 @@ const authService = { } // Create user with password + const passwordToPersist = await hashPassword(password); + const user = await databaseService.createUserWithPassword( email, - password, + passwordToPersist, username ); @@ -80,14 +83,21 @@ const authService = { throw new Error('Email verification required'); } - // Simple password verification (in production, use bcrypt) - logger.auth.login('Comparing passwords', { - inputPassword: input.password, - storedPassword: user.password, - match: user.password === input.password, + if (!isBcryptHash(user.password)) { + logger.auth.error('Stored password is not hashed; rejecting login'); + throw new Error('Invalid credentials'); + } + + const hasValidPassword = await verifyPassword( + input.password, + user.password + ); + + logger.auth.login('Password comparison result', { + hasValidPassword, }); - if (user.password !== input.password) { + if (!hasValidPassword) { logger.auth.error('Password mismatch'); throw new Error('Invalid credentials'); } @@ -162,8 +172,16 @@ const authService = { throw new Error('Cannot change password for OAuth accounts'); } - // Verify current password - if (user.password !== currentPassword) { + if (!isBcryptHash(user.password)) { + throw new Error('Password needs to be reset before it can be changed'); + } + + const currentPasswordMatches = await verifyPassword( + currentPassword, + user.password + ); + + if (!currentPasswordMatches) { throw new Error('Current password is incorrect'); } @@ -175,7 +193,7 @@ const authService = { // Update user with new password (this should be hashed before calling) const updatedUser = await databaseService.updateUser({ ...user, - password: newPassword, + password: await hashPassword(newPassword), }); return { @@ -249,10 +267,11 @@ const authService = { throw new Error('User not found'); } - // Update user with new password (this should be hashed before calling) + const hashedPassword = await hashPassword(newPassword); + const updatedUser = await databaseService.updateUser({ ...user, - password: newPassword, + password: hashedPassword, }); // Remove used token