Authentication is the front door to every application. If it is weak, nothing behind it matters. Building a secure authentication system requires understanding not just how passwords work, but how attackers exploit them and what countermeasures actually hold up under real-world conditions.
Why Passwords Alone Are Not Enough
The 2024 Verizon Data Breach Investigations Report found that over 80% of hacking-related breaches involved stolen or weak credentials. Users reuse passwords across services, choose predictable patterns, and fall for phishing attacks. Even with strong password policies, a single compromised credential can cascade across multiple systems.
This is why multifactor authentication (MFA) has become essential. MFA requires users to prove their identity using two or more independent factors: something they know (password), something they have (phone or hardware token), and something they are (biometrics).
Secure Password Hashing
The foundation of any auth system is how passwords are stored. Storing passwords in plaintext or using fast hashing algorithms like MD5 or SHA-256 is a critical vulnerability. These algorithms are designed for speed, which means attackers can compute billions of hashes per second using GPUs.
Instead, use adaptive hashing algorithms designed specifically for passwords:
bcrypt incorporates a work factor (cost parameter) that makes hashing intentionally slow. A cost factor of 12 means each hash takes roughly 250 milliseconds, which is imperceptible to a user logging in but devastating to an attacker trying to brute-force millions of hashes. bcrypt also automatically generates and stores a random salt with each hash, preventing rainbow table attacks.
Argon2 is the winner of the Password Hashing Competition and offers tunable memory and computation costs. Argon2id is the recommended variant, combining resistance to both side-channel and GPU attacks.
In Python, implementing bcrypt is straightforward. The library handles salt generation internally, and you simply compare the stored hash against the input password during login. The key point is that you never decrypt a password hash. You hash the input and compare the results.
Implementing TOTP-Based MFA
Time-based One-Time Passwords (TOTP) generate a six-digit code that changes every 30 seconds, based on a shared secret and the current time. The standard is defined in RFC 6238 and is supported by authenticator apps like Google Authenticator, Authy, and Microsoft Authenticator.
The implementation flow works as follows: during enrollment, the server generates a random secret key and presents it to the user as a QR code. The user scans it with their authenticator app, which stores the secret locally. During login, after the user provides their password, they also enter the current TOTP code. The server independently generates the expected code using the same secret and current time, then compares them.
A critical detail is the time window. Servers should accept codes from the current 30-second window as well as one window before and after to account for clock drift between the server and the user's device.
Defending Against Common Attacks
Brute Force Prevention requires rate limiting login attempts per account and per IP address. After five failed attempts, lock the account for a progressively increasing duration: 1 minute, then 5 minutes, then 30 minutes. Log all failed attempts and alert on anomalous patterns.
Credential Stuffing Defense is necessary because attackers use leaked username/password pairs from other breaches to try logging into your application. Beyond rate limiting, check submitted passwords against known breach databases (like Have I Been Pwned's API) and flag users whose credentials appear in leaks.
Session Management requires generating cryptographically random session tokens, setting appropriate expiration times, invalidating sessions on logout, and using HTTP-only secure cookies that are not accessible to JavaScript.
Account Enumeration Prevention means the login form should return the same generic error message whether the username or the password is incorrect. Different error messages reveal which usernames exist in the system.
Putting It All Together
A production-grade authentication system combines bcrypt password hashing, TOTP-based MFA, rate limiting at multiple levels, session management with secure cookies, account lockout policies, and comprehensive audit logging. Each layer addresses a different attack vector, and no single layer is sufficient on its own.
The most secure authentication system is one that assumes every other layer has already failed and still provides protection.
