Authentication is one of the few parts of a web application where a mistake rarely stays contained; a weakness in how passwords, tokens or sessions are handled can expose every user account at once rather than degrading gracefully. This article walks through the authentication patterns Codex Thrill treats as a baseline for a new web application, covering password storage, token handling, multi-factor authentication and account lockout, along with the tradeoffs each pattern involves rather than presenting them as a simple checklist.
Password storage fundamentals
Passwords should never be stored in plain text or with reversible encryption; they need to be hashed with a slow, purpose-built algorithm such as bcrypt or argon2 that is deliberately expensive to compute, which makes brute-force guessing impractical even if a database is compromised. A unique salt per password, generated automatically by these algorithms, also prevents attackers from using precomputed tables to reverse common passwords across many accounts at once.
Beyond the hashing algorithm itself, minimum password requirements should discourage obviously weak choices without becoming so strict that users resort to predictable patterns to satisfy them, such as appending a number to the same base word. Checking new passwords against known breached password lists is a more effective control than arbitrary complexity rules, since it directly blocks credentials already known to attackers rather than enforcing rules that provide only superficial protection.
- Hash with bcrypt or argon2
- Use a unique salt per password
- Check against known breached password lists
Short-lived access tokens
Access tokens used to authenticate API requests should have a short expiry, typically measured in minutes, so that a leaked token has a limited window in which it can be misused before it stops working on its own. Keeping these tokens out of persistent server-side storage and returning them only in the response body, rather than writing them to a database, also reduces the number of places an attacker could compromise to obtain valid tokens in bulk.
Short-lived tokens do mean a client application needs a mechanism to obtain a new token before the current one expires, without forcing a user to log in again every few minutes, which is where a longer-lived refresh mechanism becomes necessary. Balancing token lifetime against user convenience is a deliberate tradeoff: too short and legitimate sessions are interrupted constantly; too long and the exposure window after a leak grows correspondingly larger.
Refresh token rotation
A refresh token, used to obtain new access tokens without re-entering credentials, should be stored as an HttpOnly cookie rather than in client-side script-accessible storage, which protects it from being read by malicious JavaScript even if a cross-site scripting vulnerability exists elsewhere on the page. Storing only a hash of the refresh token server-side, rather than the token itself, limits what an attacker gains even from a database breach.
Rotating the refresh token on every use, so each refresh call issues a new token and immediately invalidates the previous one, limits the damage from a stolen refresh token: if both the legitimate user and an attacker later try to use the same old token, the reuse can be detected and the whole token family revoked. This rotation pattern adds some implementation complexity but meaningfully reduces the practical impact of a single leaked token.
- Store as an HttpOnly cookie
- Store only a hash server-side
- Rotate on every use and detect reuse
Multi-factor authentication
Requiring a second factor, such as a time-based one-time code or a push notification, in addition to a password meaningfully reduces the risk from credential leaks, since a leaked or guessed password alone is no longer sufficient to access an account. This is particularly important for accounts with administrative privileges or access to sensitive data, where the consequence of a single compromised account is significantly higher than for a typical user account.
Multi-factor authentication does add friction to the login process, so its rollout needs to balance security against usability: making it mandatory for administrative and high-privilege roles while offering it as an optional but encouraged feature for regular users is a common practical compromise. Clear recovery options for a lost second factor also need to be designed carefully, since an overly rigid recovery process can lock out legitimate users just as effectively as it blocks attackers.
Session and account lockout policy
Locking an account temporarily after a defined number of failed login attempts, rather than allowing unlimited guesses, blocks straightforward brute-force attacks while still allowing a legitimate user who mistyped a password a reasonable number of retries before being locked out. The lockout duration and attempt threshold need to be tuned to avoid becoming a denial-of-service vector itself, where an attacker deliberately triggers lockouts on known usernames to disrupt legitimate access.
Logging failed login attempts, including timing and originating information where available, gives a team visibility into whether a spike in failures reflects normal user error or a coordinated attack attempt against multiple accounts. This logging should feed into monitoring or alerting rather than sitting unreviewed in a log file, since the value of the data depends on someone actually looking at it before an attack succeeds elsewhere.
- Lock accounts after repeated failed attempts
- Tune thresholds to avoid a denial-of-service risk
- Log and monitor failed-login patterns
Conclusion
No single authentication pattern makes a web application secure on its own; the combination of strong password hashing, short-lived tokens with proper rotation, optional multi-factor authentication, and consistent server-side authorization checks together reduce the practical risk of account compromise. None of this eliminates risk entirely, and ongoing monitoring and prompt patching remain necessary. Codex Thrill builds these patterns into new web applications by default and reviews existing authentication systems against this same baseline on request.
Frequently asked questions
Is multi-factor authentication necessary for every user of a web application?
It depends on the sensitivity of the account; making it mandatory for administrative roles and offering it as an encouraged option for regular users is a common and reasonable balance between security and convenience.
Can an existing application's authentication system be upgraded without forcing all users to reset their passwords?
Usually yes, since password hashes can typically be migrated or re-hashed transparently on next login; a full forced reset is rarely necessary unless a specific breach or algorithm weakness requires it.

