Identity & Access Management

Authentication Fundamentals

Authentication answers "who are you"; authorization (Authorization Models) answers "what can you do" — conflating the two is one of the most common access-control design mistakes. Getting authentication wrong (weak hashing, no MFA, no rate limiting) undermines every authorization decision built on top of it.
  • Authentication verifies identity; authorization decides what an authenticated identity may do — treating them as one step instead of two independent decisions is a recurring design mistake
  • Password hashing must use a slow, purpose-built, salted algorithm (bcrypt, scrypt, Argon2) — a fast general-purpose hash like MD5 or bare SHA-256 lets an attacker who steals the hash table brute-force billions of guesses per second on commodity GPUs
  • MFA factors fall into three categories — something you know (password), something you have (phone, hardware key), something you are (biometric) — assurance goes up only when factors come from different categories, not from piling on more of the same one
  • Passkeys (WebAuthn) replace a shared secret with public-key challenge-response: the private key never leaves the device, so there's no password to phish and no server-side password database to breach
  • Credential stuffing replays password/username pairs leaked from one breach against every other site, banking on password reuse; defenses include rate limiting (Rate Limiting Algorithms), CAPTCHA after repeated failures, leaked-password checks at signup, and device fingerprinting
  • Exponential backoff scoped to identity+IP slows a real attacker without punishing legitimate users; a hard account lockout after N failures is itself a denial-of-service vector — anyone who knows a username can lock out its owner
Password hashing algorithms compared
AlgorithmDesign goalGPU/ASIC-resistant?Typical use
MD5Fast checksummingNo — billions of hashes/sec on a GPUNever for passwords; fine for non-security checksums
SHA-256 (unsalted, single pass)Fast general-purpose hashingNo — same GPU brute-force problemNever alone for passwords; fine as a building block inside HMAC
bcryptDeliberately slow, tunable cost factorPartially — resists early GPUs, less so ASICsLong-standing default for password storage
scryptSlow and memory-hardYes — memory cost blocks cheap parallel hardwarePassword storage where memory-hardness matters most
Argon2 (id variant)Winner of the Password Hashing Competition; tunable time/memory/parallelismYes — designed to resist GPU/ASIC/FPGACurrent best-practice default for new systems
Password login with salted-hash check and optional MFA
The stored hash is never reversed — the login attempt is re-hashed with the same salt and compared
Validating a password via a PasswordEncoder-style interface
interface PasswordEncoder {
    String encode(CharSequence rawPassword);
    boolean matches(CharSequence rawPassword, String encodedPassword);
}

class LoginService {
    private final PasswordEncoder encoder; // backed by BCrypt/Argon2, never a raw digest
    private final UserRepository users;

    boolean authenticate(String username, String rawPassword) {
        User user = users.findByUsername(username).orElse(null);
        if (user == null) {
            encoder.matches(rawPassword, DUMMY_HASH); // do the same work for unknown users
            return false;
        }
        return encoder.matches(rawPassword, user.getPasswordHash());
    }
}
matches() re-derives the hash using the stored salt and cost factor and compares — a correctly hashed password cannot be decrypted at all, only re-verified
Sources
  • Solving Identity Management in Modern Applications (2nd ed.)Ch. 2 — Authentication Fundamentals
  • System Design: The Big Archive (2024 ed.)Fundamentals — Password Hashing & MFA