Secure login flow best practices: the short list

Six rules. Apply all of them and you've covered 95% of the attack surface. Skip one and you're in the other 5%.

· LoginWith team

There are long OWASP cheat sheets for authentication security. Most teams implement half of them, ship, and discover the gaps during a breach. Here’s the short version that catches the common mistakes.

1. Rate-limit by account, not IP

IP-based rate limits are useless against credential stuffing — every attempt comes from a different residential proxy. Limit by account: 5 failed attempts in 5 minutes triggers a 15-minute lockout, escalating to 1 hour on repeat offenders. Apply the same policy to password reset and MFA endpoints.

2. Rotate the session ID on every privilege change

Session fixation is a 20-year-old bug that still appears in audits. When a user signs in, signs up, elevates privilege (MFA, impersonation), or changes their password, generate a new session ID and invalidate the old one. Every web framework does this out of the box. Every hand-rolled auth system forgets.

3. Cookies: Secure; HttpOnly; SameSite=Lax

This is the cookie baseline. HttpOnly blocks JavaScript access (defeats XSS token theft). Secure requires HTTPS. SameSite=Lax blocks classic CSRF and is the browser default now. For cross-site contexts (embeds, etc.), use SameSite=None; Secure; Partitioned so CHIPS works correctly.

4. Hash tokens at rest

Session tokens, API keys, password reset tokens — all are credentials. If a read-only DB dump leaks, hashed tokens reveal nothing usable. Store them as SHA-256 hashes, hash on lookup, compare. Tokens have enough entropy that bcrypt-style work factors are unnecessary.

5. Verify state and PKCE on OAuth callbacks

state is the CSRF defense — a random, per-request nonce that ties the callback to the session that started the flow. PKCE is the code-interception defense. Both are required for a secure OAuth flow; neither is optional even if you “just want to ship it.” Validate both on every callback.

Anything sent via email is a bearer token that might sit in a mailbox indefinitely, get forwarded, or be searched. Keep expiration windows tight:

  • Password reset tokens: 30 minutes
  • Magic links: 15 minutes
  • MFA one-time codes: 10 minutes

And rotate on first use — a single-use token that’s already been used must be rejected on replay, even within its expiration window.

Done

These six cover most of what goes wrong. Everything else (CSP, CSRF tokens, step-up auth, device binding) is either layered on top or specific to your threat model.

Want auth that just works?

Get started with LoginWith