Password & Authentication Best Practices
Authentication is one of the most attacked parts of any application, and small implementation choices — how passwords are stored, how login attempts are rate-limited, what happens on a failed login — have an outsized effect on how resistant a system actually is to real attacks.
Last updated 2026-09-08
Hash passwords with bcrypt, Argon2, or scrypt — never store them plainly or with a fast hash
Passwords must never be stored in plain text, and fast general-purpose hashes like SHA-256 or MD5 are also unsuitable — they're designed to be fast, which makes brute-forcing a stolen hash database fast too. Purpose-built password hashing algorithms are deliberately slow and include built-in salting.
await bcrypt.hash(password, 12) // deliberately slow, salted automaticallycrypto.createHash('sha256').update(password).digest('hex') // fast hash — brute-forceable at scaleEnforce length over arbitrary complexity rules
Forcing a mix of uppercase, numbers, and symbols often pushes users toward predictable patterns (Password1!) rather than genuinely strong passwords. A longer minimum length, without excessive composition rules, correlates better with real resistance to guessing and cracking.
Rate-limit login attempts
Without rate-limiting, an attacker can attempt thousands of password guesses per second against a login endpoint. Locking out or slowing down after a handful of failed attempts (per account and per IP) makes brute-force attacks impractical without meaningfully inconveniencing legitimate users.
Use the same generic error message for 'wrong password' and 'account doesn't exist'
A login form that says 'no account with that email' versus 'incorrect password' leaks which emails are registered — useful information for an attacker enumerating valid accounts before a targeted attack. A single generic 'invalid email or password' message avoids this leak.
Offer and encourage multi-factor authentication
A compromised password stops being sufficient to breach an account when a second factor is required. Even optional MFA, clearly offered rather than buried in settings, meaningfully reduces account-takeover risk for the users who enable it.
Never log passwords, even accidentally
Request-logging middleware that captures full request bodies can inadvertently log plaintext passwords from login or signup requests. Explicitly scrub or exclude password fields from any logging layer, rather than assuming it won't happen.
Invalidate sessions on password change
If a user changes their password (especially after suspecting compromise), any existing sessions — including ones an attacker might be holding — should be invalidated, not left valid until they naturally expire.
Common Mistakes to Avoid
- ⚠Hashing passwords with a fast, general-purpose hash function instead of bcrypt/Argon2/scrypt
- ⚠Storing passwords with reversible encryption 'for convenience' instead of hashing them
- ⚠Forcing complex composition rules that push users toward predictable, weak patterns
- ⚠Different error messages for 'wrong password' vs 'no such account', leaking valid emails
- ⚠No rate-limiting on login endpoints, leaving them open to brute-force attempts
- ⚠Logging full request bodies without excluding password fields
Frequently Asked Questions
Is bcrypt still considered secure in 2026?
Yes — bcrypt remains a widely trusted, industry-standard choice, though Argon2 (the winner of the Password Hashing Competition) is increasingly recommended for new systems specifically designed with memory-hardness against GPU-based cracking in mind.
How long should passwords be required to be?
A minimum of 12 characters is a commonly recommended baseline today, prioritizing length over forced character-type complexity, which correlates better with actual resistance to cracking.
Should I force periodic password changes?
Current guidance from most security bodies (including NIST) advises against mandatory periodic password rotation for its own sake — it tends to produce weaker, more predictable passwords as users adapt to the requirement, without a clear security benefit.