Authentication decisions are security decisions. Get the fundamentals right before adding a single provider or UI flow.
Passwords, if you store them at all
- Never store passwords in plaintext or with a fast hash (MD5, SHA-256 alone). Use a slow, salted algorithm designed for passwords: bcrypt, scrypt, or argon2id. Argon2id is the current best default when available.
- Never roll your own hashing scheme or "improve" one with a custom pepper scheme you invented — use the library's built-in salt handling.
- Enforce a minimum length (12+ characters), not arbitrary complexity rules (mandatory symbols/numbers) — length beats complexity, and complexity rules push users toward predictable patterns.
Sessions and tokens
- Every authenticated request must be tied to a session or token that can be revoked server-side. If you use JWTs, keep them short-lived and pair them with a server-side revocation mechanism (refresh token rotation, a denylist, or a session table) — a stateless JWT alone cannot be logged out.
- Never put sensitive data (roles, permissions, PII) in a client-readable token without also re-verifying it server-side on every privileged action — a token is a claim, not a guarantee, until the server checks it against current state.
Verification before trust
- Always verify email ownership (or phone, for SMS-based flows) before treating an account as fully trusted — an unverified email should not be able to reset a password or receive account-critical notifications as if verified.
- Rate-limit login attempts per account AND per IP independently; a limit on only one of the two is trivially bypassed (distributed credential stuffing vs. a single attacker cycling accounts).
Password reset flows
- Reset tokens must be single-use, time-limited (15–60 minutes is typical), and invalidate all other outstanding reset tokens for that account when one is used.
- Never reveal via response timing or message text whether an email address has an account — "if that email exists, we sent a link," for both cases, with the same response shape and similar latency.
Multi-factor and account recovery
- If you offer MFA, always provide a documented recovery path (backup codes, admin-assisted recovery) — a user permanently locked out of their own account is a support disaster and a churn driver.
- Never let a password reset alone silently disable a user's MFA — that defeats the entire point of MFA.
Authorization is not authentication
- Authenticating who someone is says nothing about what they're allowed to do. Every privileged action needs its own authorization check server-side (role, ownership, tenant boundary) — never infer authorization from the mere presence of a valid session.
- Re-check ownership/authorization on every mutating request, even if the UI already hid the button — a hidden button is not a security control.
What builds on this
The concrete flows below — password-based login, OAuth/social login, and the specifics of keeping a session secure over its full lifetime — all assume everything above holds. Get this module right first; the concrete flows are where these rules get applied, not reinvented.
Comments (0)
Sign in to comment. Sign in
No comments yet. Be the first to add one.