Cryptographic guardian! Architect Vitruvius introduces you to the deepest secrets of protecting the Empire's vault codes. Password hashing is the art of creating irreversible ciphers that protect legionaries' secrets even from the fiercest enemies!
In the legionary camp, every resource must be protected. Similarly in applications - user passwords are the most valuable resources that require the best protection methods.
Password hashing is the process of transforming a password into an irreversible string of characters (hash). It's like creating a unique fingerprint for each password - you can verify it, but you cannot reconstruct the original password from it.
1// BAD APPROACH - simple encryption
2const encryptedPassword = encrypt('my-secret-password', 'encryption-key');
3// Can be decrypted: decrypt(encryptedPassword, 'encryption-key')
4
5// GOOD APPROACH - hashing
6const hashedPassword = await bcrypt.hash('my-secret-password', 12);
7// The process cannot be reversed!1// npm install bcrypt
2// npm install -D @types/bcrypt
3
4import * as bcrypt from 'bcrypt';
5
6@Injectable()
7export class PasswordService {
8 private readonly saltRounds = 12; // Hashing strength
9
10 async hashPassword(plainPassword: string): Promise<string> {
11 console.log('Creating secure password hash...');
12
13 // Generate salt and hash
14 const hashedPassword = await bcrypt.hash(plainPassword, this.saltRounds);
15
16 console.log(`Password hashed: ${hashedPassword.substring(0, 20)}...`);
17
18 return hashedPassword;
19 }
20
21 async verifyPassword(
22 plainPassword: string,
23 hashedPassword: string
24 ): Promise<boolean> {
25 console.log('Verifying password...');
26
27 const isValid = await bcrypt.compare(plainPassword, hashedPassword);
28
29 console.log(`${isValid ? 'Valid' : 'Invalid'} verification result: ${isValid}`);
30
31 return isValid;
32 }
33
34 // Check if the password needs re-hashing (change in saltRounds)
35 async needsRehash(hashedPassword: string): Promise<boolean> {
36 try {
37 // bcrypt automatically detects the password strength from the hash
38 const currentRounds = this.extractSaltRounds(hashedPassword);
39 return currentRounds < this.saltRounds;
40 } catch (error) {
41 return true; // If it cannot be determined, it's better to re-hash
42 }
43 }
44
45 private extractSaltRounds(hash: string): number {
46 // bcrypt format: $2b$12$...
47 const parts = hash.split('$');
48 return parseInt(parts[2], 10);
49 }
50}Remember: a password is the key to a legionary's vault - it must be protected like the most valuable resource in the application!
In the next exercise, we will learn about Refresh Tokens - the system for extending passes to the fort system!