Overview
Secure password hashing with Argon2id. Includes strength checking and rehash detection.
Features
- Argon2id hashing
- OWASP configuration
- Strength checking
- Rehash detection
Installation
npx hanma add password --framework nest
Dependencies
argon2
Code
import * as argon2 from "argon2";
// Argon2id configuration (OWASP recommended)
const HASH_OPTIONS: argon2.Options = {
type: argon2.argon2id,
memoryCost: 65536, // 64 MB
timeCost: 3, // Number of iterations
parallelism: 4, // Degree of parallelism
hashLength: 32, // Output hash length
};
/**
* Hash a password using Argon2id.
*/
export async function hashPassword(password: string): Promise<string> {
if (!password || password.length === 0) {
throw new Error("Password cannot be empty");
}
return argon2.hash(password, HASH_OPTIONS);
}
/**
* Verify a password against a hash.
*/
export async function verifyPassword(
hash: string,
password: string
): Promise<boolean> {
if (!hash || !password) {
return false;
}
try {
return await argon2.verify(hash, password);
} catch {
return false;
}
}
/**
* Check if a hash needs to be rehashed (e.g., after security upgrade).
*/
export function needsRehash(hash: string): boolean {
return argon2.needsRehash(hash, HASH_OPTIONS);
}
/**
* Rehash password if needed (call after successful verification).
*/
export async function rehashIfNeeded(
hash: string,
password: string
): Promise<string | null> {
if (needsRehash(hash)) {
return hashPassword(password);
}
return null;
}
// Password strength validation
export interface PasswordStrength {
score: number; // 0-4
feedback: string[];
}
export function checkPasswordStrength(password: string): PasswordStrength {
const feedback: string[] = [];
let score = 0;
if (password.length >= 8) score++;
else feedback.push("Password should be at least 8 characters");
if (password.length >= 12) score++;
if (/[a-z]/.test(password) && /[A-Z]/.test(password)) {
score++;
} else {
feedback.push("Password should include uppercase and lowercase letters");
}
if (/\d/.test(password)) {
score++;
} else {
feedback.push("Password should include at least one number");
}
if (/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
score++;
} else {
feedback.push("Password should include at least one special character");
}
// Common patterns to avoid
const commonPatterns = [
/^123/,
/password/i,
/qwerty/i,
/abc123/i,
/(.)\1{2,}/, // Repeated characters
];
for (const pattern of commonPatterns) {
if (pattern.test(password)) {
score = Math.max(0, score - 1);
feedback.push("Avoid common password patterns");
break;
}
}
return { score: Math.min(4, score), feedback };
}
// Usage:
/*
import { hashPassword, verifyPassword, checkPasswordStrength } from "./utils/password";
@Injectable()
export class AuthService {
async register(email: string, password: string) {
const strength = checkPasswordStrength(password);
if (strength.score < 3) {
throw new BadRequestException({
message: "Password too weak",
feedback: strength.feedback,
});
}
const hashedPassword = await hashPassword(password);
// Save user with hashedPassword
}
async login(email: string, password: string) {
const user = await this.findByEmail(email);
const isValid = await verifyPassword(user.password, password);
if (!isValid) {
throw new UnauthorizedException("Invalid credentials");
}
// Check if password needs rehashing
const newHash = await rehashIfNeeded(user.password, password);
if (newHash) {
await this.updatePassword(user.id, newHash);
}
return user;
}
}
*/
Usage
const hash = await hashPassword(password);
const valid = await verifyPassword(hash, password);
Dependencies
argon2
Frequently Asked Questions
How do I install Password Utilities?
Run the following command:
npx hanma add password --framework nestWhat dependencies are required?
This snippet requires: argon2. Make sure to install them before using the snippet.
How do I use this snippet?
Copy the code and paste it into your project. The snippet will be saved to
src/utils/password.ts.Can I customize this snippet?
Yes! All snippets are copy-paste code that you own. Feel free to modify them to fit your needs.
Does this work with other frameworks?
This snippet is designed for the specific framework. Check the other framework pages for equivalent implementations.