In this comprehensive guide, we’ll explore the foundational elements of secure authentication.
We’ll start with the best practices for creating and managing passwords,
delve into the importance of generating secure hashes,
and walk through the process of comparing hashes during login.
A good strong password is essential for securing user accounts and protecting sensitive information.
According to the OWASP (Open Web Application Security Project) guidelines,
a strong password should adhere to several key principles to minimize the risk of unauthorized access.
To ensure that our application adheres to strong password practices, we’ll be using the
OWASP Password Strength Test library by NowSecure.
This library is designed to help enforce password requirements on the client side and validate passwords on the authentication service.
1import owasp from 'owasp-password-strength-test';
2
3owasp.config({
4 allowPassphrases: true,
5 maxLength: 128,
6 minLength: 10,
7 minPhraseLength: 20,
8 minOptionalTestsToPass: 4,
9});
10
11const passwdStrength = owasp.test(value);
12interface PasswordInputProps {
13 title?: string;
14 characterLimit?: number;
15}
16
17const PasswordInput = ({
18 title = '',
19 characterLimit = 128,
20}: PasswordInputProps) => {
21 const [value, setValue] = useState('');
22 const passwdStrength = owasp.test(value);
23
24 const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
25 const { value } = e.target;
26 if (value.length > characterLimit) return;
27 setValue(value.replace(/[^+a-z0-9áéíóúñü_\-.!@#$%^&*(){}[\]]/gi, ''));
28 };
29
30 const isError = value.length > 0 && passwdStrength.errors.length > 0 || false;
31
32 return (
33 <div className={`${styles['password-input']}
34 ${isError ? styles['password-input--error'] : ''}`}>
35 <div className={styles['password-input__label']}>
36 <p>{title}</p>
37 <span>*</span>
38 <cite>{`${value.length} / ${characterLimit}`}</cite>
39 </div>
40 <input
41 tabIndex={0}
42 placeholder="Enter your password"
43 onChange={handleChange}
44 type="password"
45 value={value}
46 />
47 <div className={styles['password-input__strength']}>
48 <cite className="error">
49 {value.length > 0 ? passwdStrength?.errors?.[0] : ''}
50 </cite>
51 <cite>{passwdStrength.strong ? 'Strong' : 'Weak'}</cite>
52 </div>
53 </div>
54 );
55};
56
57export default PasswordInput;
58
Password
*0 / 128To ensure that the password meets the minimum requirements, we should also validate it on the server-side before hashing it.
We can use the same OWASP library to validate the password on the server-side as well.
When storing passwords in a database, it’s crucial to hash them securely to prevent unauthorized access.
We’ll be using the bcrypt.js library to hash and compare passwords in our application.
1import bcrypt from 'bcrypt';
2
3export const generateHash = (password: string) =>
4 new Promise<string>((resolve, reject) => {
5 bcrypt.hash(password, 10, (error, hash) => {
6 if (error) {
7 return reject(errors.HASHING_FAILED);
8 }
9 return resolve(hash);
10 });
11 });
1$2b$10$<22-character-salt><31-character-hash>
Bcrypt securely hashes passwords by generating a unique, random salt for each password, ensuring that even identical passwords result in different hashes, effectively protecting against rainbow table and brute-force attacks.
You can learn more about bcrypt here.
When a user logs in, we need to compare the hashed password stored in the database with the hashed password entered by the user.
1import bcrypt from 'bcrypt';
2
3export const verifyHash = (password: string, hash: string) =>
4 new Promise<boolean>((resolve, reject) => {
5 bcrypt.compare(password, hash, (error, result) => {
6 if (error) {
7 return reject(errors.HASH_VERIFICATION_FAILED);
8 }
9 return resolve(result);
10 });
11 });
Now that you’ve mastered the basics of secure password management, you’re ready to take your authentication system to the next level.
Check out the following blog posts to learn more about securing user sessions and implementing JWT authentication in your application:
Mastering JWT in Node.js: Secure Token Generation and Verification