WritingCommon Web Authentication Mistakes Developers Make (and How to Fix Them) — Clixo
6 min readauthentication, web-security, owasp, session-management, passwords

Common Web Authentication Mistakes Developers Make (and How to Fix Them)

The most common web authentication mistakes developers make — from weak password hashing to missing rate limits — and the specific fixes for each one.

Authentication failures are the second most common category in the OWASP Top 10, and the failures tend to be specific and repeatable. The same mistakes appear across codebases regardless of framework or language. They often stem not from ignorance but from prioritizing speed — using the convenient approach rather than the correct one, or skipping the controls that seem unlikely to matter in practice.

These mistakes matter in practice. Here are the ones that appear most frequently in real applications.

Common Authentication Mistakes in Web Applications

Rolling custom authentication instead of using a proven library

Building authentication from scratch is a significant undertaking. It requires correct implementations of password hashing, session management, token generation, MFA, account recovery, and brute-force protection — all areas where subtle errors have large consequences.

Most teams building custom auth do so because they want control or because integrating a library feels like overhead at the start of a project. Six months later, they have an authentication system that has not been audited, does not receive security updates, and has implementation details that are difficult to review.

Use an established authentication library for your stack — Passport.js, NextAuth.js, Auth.js, Devise, or a managed authentication service. Reserve custom authentication for cases where you have specific requirements that off-the-shelf solutions genuinely cannot meet.

Weak password hashing

Storing passwords with MD5, SHA-1, or even unsalted SHA-256 is a critical vulnerability. These algorithms are fast by design, which means an attacker who obtains your password database can run billions of hash attempts per second using commodity hardware or cloud GPU instances.

Use a purpose-built password hashing algorithm that is intentionally slow and includes a work factor you can tune over time:

  • bcrypt: widely supported, well-audited, a good default for most applications
  • Argon2id: the current recommendation from OWASP and the winner of the Password Hashing Competition, preferred for new implementations
  • scrypt: memory-hard, suitable when you want to resist GPU-based cracking

Never implement your own hashing scheme. Never store passwords in plaintext or with reversible encryption.

Missing rate limiting on authentication endpoints

An endpoint that accepts unlimited login attempts lets attackers run credential stuffing or brute-force attacks without friction. Credential stuffing — using username/password pairs from previous breaches — succeeds at scale against applications with no rate limiting because a meaningful percentage of users reuse credentials across services.

Apply rate limiting specifically to:

  • Login endpoints (per IP, per account, or both)
  • Password reset request endpoints
  • OTP or MFA code submission endpoints
  • Account creation endpoints (to limit fake account creation at scale)

Exponential backoff after failed attempts and temporary account lockout are appropriate responses to repeated failures. Be careful to lock on incorrect credentials without revealing whether the lockout was triggered by a valid account, to avoid account enumeration.

Predictable or insufficient password reset flows

Password reset is a secondary authentication path, and it needs the same security properties as the primary one. Common weaknesses:

  • Short-lived tokens with low entropy (a 6-digit numeric code is guessable in at most a million attempts without rate limiting)
  • Reset tokens that do not expire or that remain valid after use
  • Reset links delivered over email but also embedded in logs
  • Security questions as the reset mechanism (answers are guessable or discoverable)

Generate reset tokens using a cryptographically secure random generator with at least 128 bits of entropy. Expire them after a short window (15 to 30 minutes). Invalidate them immediately after use. Send them only via the registered email address. Do not use security questions.

Missing multi-factor authentication for sensitive operations

Passwords alone are increasingly insufficient. They are reused, phished, leaked in breaches, and guessed. Multi-factor authentication eliminates credential-only compromises by requiring a second factor the attacker does not have.

MFA is not optional for applications handling financial data, personal health information, or any functionality with significant consequences if an account is compromised. It should be enabled by default, not buried in settings.

For implementation: TOTP (time-based one-time passwords, as in Google Authenticator) and hardware security keys (WebAuthn/FIDO2) are the most phishing-resistant options. SMS-based OTP is better than nothing but is vulnerable to SIM-swapping and should not be the only available MFA method for high-risk accounts.

Insecure session management

Common session management mistakes:

  • Not regenerating the session ID after successful login (session fixation vulnerability)
  • Using session IDs with insufficient entropy (guessable IDs allow session hijacking)
  • Not expiring sessions after inactivity
  • Not invalidating all sessions on password change or suspicious activity

Session IDs should be at least 128 bits of entropy, generated by a cryptographically secure random number generator. Regenerate them on privilege elevation (after login, after sudo-style re-authentication). Implement absolute and idle timeouts. On logout, invalidate the server-side session record — do not just clear the client-side cookie.

Not invalidating tokens on logout

For JWT-based authentication, a common mistake is clearing the client-side token on logout but not maintaining a server-side blocklist. The cleared token exists only in browser memory, but if it was logged, captured, or copied before logout, it remains valid until it expires.

If your application logs out users for security reasons — account suspension, detected compromise, forced re-authentication — you need a mechanism to invalidate outstanding tokens. Short expiry windows reduce the window; a server-side blocklist eliminates it.

Verbose error messages that enable account enumeration

Returning different error messages for "user does not exist" versus "incorrect password" tells attackers which usernames are registered in your system. They can then concentrate credential stuffing efforts on valid accounts.

Return a generic message — "Invalid credentials" — for any failed login attempt regardless of whether the username exists. Apply the same principle to password reset: respond identically whether or not the email is registered.

Not monitoring authentication events

Failed logins, password changes, MFA additions or removals, and new device sign-ins are high-signal security events. Without logging them and alerting on anomalous patterns, you have no way to detect a credential stuffing campaign in progress, a compromised account being accessed from a new location, or a password change that the user did not make.

Log authentication events with enough context to be useful: timestamp, user identifier (not the password), IP address, user-agent, and success or failure. Ship these logs to a system that can alert on patterns — many consecutive failures, successful login from an unusual geography, MFA device change followed immediately by a sensitive operation.

Building a product that handles user authentication and want it done properly from day one? Start a build.