Authentication & Authorization: Fundamentals
Authentication (AuthN) verifies identity — who are you? Authorization (AuthZ) determines permissions — what are you allowed to do? They are distinct concerns and should be implemented separately.
Sessions vs Tokens
Session-based (stateful):
1. User logs in → server creates session in DB/Redis → sets cookie with session ID
2. Subsequent requests → server looks up session ID → gets user data
3. Logout → delete session from storage
Pros: easy revocation, smaller cookie, server controls session lifetime
Cons: server must store sessions (scales horizontally with shared Redis/DB)
Token-based (stateless JWT):
1. User logs in → server generates signed JWT → client stores token
2. Subsequent requests → client sends JWT → server validates signature (no DB lookup)
3. Logout → client deletes token (server can't revoke without a blocklist)
Pros: stateless — scales without shared storage, works across microservices
Cons: can't revoke individual tokens without blocklist; sensitive data in payload (not encrypted)
Recommendation:
Public APIs → JWT (stateless, good for third-party consumers)
Web apps → HTTP-only cookies with session OR JWT in HttpOnly cookie
Microservices → JWT passed in Authorization headerPassword Storage
Never store passwords in plaintext or with reversible encryption.
Use adaptive one-way hashing with a salt:
bcrypt: industry standard. Cost factor makes brute-force expensive.
bcrypt.hash("password", 12) — cost factor 12 (~250ms)
Argon2id: winner of Password Hashing Competition (2015). Preferred for new systems.
Memory-hard — resistant to GPU/ASIC cracking.
argon2id({ memory: 65536, iterations: 3, parallelism: 4 })
scrypt: similar to Argon2, memory-hard, PBKDF2 upgrade.
Avoid: MD5, SHA-1, SHA-256 without salt/iterations — too fast for passwords.
PBKDF2 is acceptable but less resistant than Argon2 or bcrypt.
Salt: generated per-password (stored with hash). Prevents rainbow tables.
bcrypt/Argon2 handle salting automatically.Cookie Security
Set-Cookie: session=abc123;
HttpOnly; // JS cannot read — XSS protection
Secure; // HTTPS only
SameSite=Strict; // never sent cross-site — CSRF protection
// SameSite=Lax: sent on top-level navigations (GET)
// SameSite=None: cross-site (requires Secure)
Path=/;
Max-Age=3600; // 1 hour (seconds)
Domain=example.comMulti-Factor Authentication (MFA)
TOTP (Time-based OTP): Google Authenticator, Authy — generates 6-digit code every 30s from shared secret (RFC 6238)
SMS OTP: one-time code via SMS — convenient but vulnerable to SIM swap attacks
FIDO2 / WebAuthn: hardware security keys (YubiKey) or biometrics — phishing-resistant, strongest option
Push notifications: Duo, Okta — approve/deny on mobile app
Recovery codes: backup one-time codes — store hashed, never plaintext
TOTP implementation: use speakeasy or otplib (Node.js), pyotp (Python)
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free