Executive Summary & Authentication Philosophy
•The Fallacy of "Just Add a Login Form"
For most engineers, authentication is treated as a solved checkbox: a login form, a table of hashed passwords, a session cookie, done. That framing is exactly what produces the majority of real-world breaches — not because engineers are careless, but because "authentication" is not one problem. It is at least four distinct, separable concerns that most tutorials and starter templates silently conflate into a single step.
Those four concerns are Identification (a client claiming to be someone — a username, an email address), Authentication (proving that claim — a password, a biometric, a possession factor), Session/Continuity (how the system remembers that proof across subsequent requests without re-proving it every time), and Authorization (what the now-proven identity is actually allowed to do). Conflating Authentication with Authorization — treating "they're logged in" as equivalent to "they can touch anything the session touches" — is the root of most privilege-escalation bugs. Conflating Identification with Authentication — trusting a username field as if it were proof of anything — is the root of most impersonation and IDOR bugs.
The stakes compound because these four concerns sit in a pipeline: a failure anywhere upstream inherits the blast radius of everything downstream. A weak Identification step doesn't just leak one field, it inherits whatever the Authorization layer behind it was willing to trust. Nearly every major consumer data breach of the last decade traces back to a failure in exactly one of these four concerns, not all four simultaneously — which means the correct engineering mental model is "four separately hardened doors," not "one hardened castle."
The Four Concerns Most Login Forms Conflate
Identification
Client claims: "I am user@example.com"
Authentication
Password / biometric / possession factor
Session / Continuity
Cookie, session ID, or bearer token
Authorization
What this identity is actually allowed to touch
•The Physics of Trust: Why Authentication Is a Cryptography Problem, Not a Feature
Just as storage systems obey the physics of hardware latency, authentication systems obey the physics of cryptographic cost — a deliberately engineered asymmetry where proving a legitimate credential must stay cheap for the real user, while forging or brute-forcing one must stay astronomically expensive for an attacker. Every authentication architecture, underneath its login form, is really a series of decisions about where to sit on this cost curve.
| Cryptographic Operation | Mechanism | Typical Time | Why It's Engineered This Way |
|---|---|---|---|
| Argon2id Password Hash | Memory-hard KDF | ~250 – 500 ms | Deliberately slow and memory-hungry — defeats GPU/ASIC brute-force farms |
| bcrypt Hash (cost factor 12) | Blowfish-based KDF | ~250 ms | Older standard, still safe — slow by design via repeated key-setup rounds |
| Raw SHA-256 (never for passwords) | Fast cryptographic hash | ~0.001 ms | Why hashing alone is unsafe for credentials — billions of guesses/sec on a commodity GPU |
| HMAC-SHA256 JWT Verify | Symmetric MAC | ~0.001 – 0.005 ms | Fast, but requires the verifying server to hold the same secret as the signer |
| RSA-2048 Signature Verify | Asymmetric (public key) | ~0.05 ms | Verification is the cheap operation by design — enables trust without a shared secret |
| RSA-2048 Signature Sign | Asymmetric (private key) | ~1 – 2 ms | Signing is deliberately the expensive asymmetric operation |
| ECDSA (ES256) Signature Verify | Asymmetric, elliptic curve | ~0.3 – 0.5 ms | Smaller keys than RSA, but verification is actually slower — a trade-off many teams get backwards |
| Full OAuth 2.0 Code Exchange | Network round-trip | ~100 – 400 ms | Network-bound, not cryptography — multiple redirects plus a server-to-server call |
ms = milliseconds · KDF = Key Derivation Function · MAC = Message Authentication Code. Timings are approximate, measured on commodity server hardware, and vary by library and key size.
•The Evolution of Authentication Eras
Authentication has evolved in response to two forces expanding at once: the growing sophistication of attackers, and the growing variety of client shapes a system has to trust — from a single browser talking to a single server, to mobile apps, single-page apps, third-party integrations, and now non-human AI agents. Each era below isn't a wholesale replacement of the one before it so much as a response to a client shape the previous era's assumptions no longer held for.
- Era 1 — Basic & Plaintext Authentication (1990s–early 2000s): HTTP Basic Auth and often-unsalted password storage, built for a world of one trusted server and a browser willing to resend credentials with every single request — there was no separate "proof" step distinct from the credential itself.
- Era 2 — Server-Side Sessions & Cookies (late 1990s–2000s): the password is verified once, a random session ID is minted and stored server-side, and the browser is trusted to carry only that ID back on every request. This era invented the authentication/session split, but assumed one server — or one shared session store — could always see every active session.
- Era 3 — Federated & Stateless Tokens (2007–2010s): SAMLSecurity Assertion Markup Language — an XML-based standard for exchanging authentication and authorization data, widely used for enterprise single sign-on., then OAuth 2.0An authorization framework that lets a user grant one application limited access to their data on another service, without ever sharing their password with the requesting app. and OpenID ConnectAn identity layer built on top of OAuth 2.0, adding a standardized, signed ID Token so a relying application can verify who a user is, not just what it's allowed to access., then JWTs — driven by mobile apps and third-party integrations that broke the "server always has the session in memory" assumption. What was needed instead was portable, self-contained, cryptographically verifiable proof that any server, even one belonging to a different company, could check without a shared session store.
- Era 4 — Passwordless & Possession-Based Authentication (2020s–present): WebAuthnA W3C browser standard for public-key-based authentication, letting a device prove possession of a private key instead of a password — the foundation passkeys are built on. and passkeys, driven by the realization that the password itself, not the session or token mechanics wrapped around it, had become the actual weakest link — phishing, credential reuse, breach-and-replay. The innovation is removing the shared secret entirely, replacing "something you know" with cryptographic possession of a private key that never leaves the user's device.
Four Eras, Each a Response to the Previous Era's Breaking Point
Basic & Plaintext
1990s
Sessions & Cookies
2000s
Federated Tokens (OAuth / JWT)
2007 – 2010s
Passwordless (Passkeys)
2020s – present
Identity & Cryptographic Mechanics
•Authentication vs Authorization vs Identity
Identity is the umbrella concept — a persistent record of "who this is" that outlives any single session or token, typically anchored to a stable identifier like a user ID or email address. It doesn't expire when a session ends; it's the thing every session and token ultimately points back to.
Authentication is the verification event — it happens at specific points in time (login, a token refresh, a re-auth prompt before a sensitive action) and its output is a claim of identity with a confidence level, not a permanent state. Being authenticated an hour ago says nothing about whether you're still the one holding the device right now.
Authorization is a separate question altogether, re-evaluated continuously: given this identity, is this specific action on this specific resource allowed right now. Treating authorization as a static property decided once at login — rather than re-checked on every request — is one of the most common real-world architectural mistakes, since permissions can change mid-session (a role revoked, an account suspended) and a system that only checks at login won't notice until the next one.
- Identity is a noun — the persistent record of who someone is, often represented by a stable identifier (a UUID, an email) that outlives any single session.
- Authentication and Authorization are verbs — authentication is verified once per session/token lifetime, while authorization must be re-evaluated on every single request, because permissions can change between requests even when identity hasn't.
Three Different Questions, Answered at Three Different Frequencies
Identity
Persistent record — outlives any session
Authentication
A point-in-time proof event
Authorization
Can change even mid-session
•Hashing vs Encryption vs Signing: The Three Pillars of Credential Security
These three cryptographic primitives are routinely confused by engineers, yet solve entirely different problems — and picking the wrong one for a given job, such as encrypting a password instead of hashing it, is a critical and recurring class of vulnerability.
- Hashing is one-way and irreversible by design — a password hash can never be 'decrypted' back to the original password, only compared against a fresh hash of an attempted password. This is precisely why hashing, not encryption, is correct for stored credentials.
- Encryption is two-way and reversible with the right key — used when the original plaintext genuinely needs to be recovered later (e.g. a stored API secret an application must send upstream), never for passwords, since anyone who steals the encryption key recovers every password in cleartext instantly.
- Signing proves authenticity and integrity, not secrecy — a signature (HMACHash-based Message Authentication Code — a symmetric technique where the same secret key both signs and verifies data, proving it wasn't tampered with by anyone lacking that key. or an asymmetric signature) proves 'this data came from someone holding a specific key and hasn't been altered,' while leaving the underlying data itself completely readable.
- A JWTJSON Web Token — a compact, signed token format (header.payload.signature) that carries identity claims the receiving server can verify without a database lookup. is signed, not encrypted, by default — its payload (username, roles, expiry) is base64-encoded, not secret, and is readable by anyone who intercepts it. Putting sensitive data in a standard JWT payload is a common and serious mistake.
- Salting defends hashing against precomputation — a unique random salt per credential means an attacker can't reuse a single precomputed Rainbow TableA precomputed lookup table of hash-to-plaintext mappings, used to reverse unsalted password hashes quickly — defeated by adding a unique salt to every hash. across every user in a breached database, forcing them to attack each hash individually.
- Peppering adds a server-side secret on top of salting — a fixed, application-wide secret mixed into every hash, which stays outside the breached database dump if the database and application secrets are stored separately, buying defense-in-depth even after a DB-only breach.
- Choosing the wrong primitive doesn't just weaken security incrementally — it changes the entire threat model. An encrypted password store means one leaked key equals every password recovered at once; a hashed store means an attacker must burn real, per-credential compute even after a full breach.
•Symmetric vs Asymmetric Crypto Under the Hood: HMAC vs RSA vs ECDSA
The core engineering trade-off: symmetric crypto (one shared secret) is fast and simple but requires every party who needs to verify to also be trusted with the power to forge, while asymmetric crypto (a public/private key pair) sacrifices some speed for a fundamentally different trust model where verification doesn't require the power to sign.
- Symmetric (HMAC): a single shared secret both signs and verifies. Fast, simple, ideal for closed systems where the signer and every verifier are the same trusted first party (e.g. a company's own backend microservices sharing one secret).
- Asymmetric (RSAAn asymmetric cryptographic algorithm based on the difficulty of factoring large numbers, widely used for both encryption and digital signatures, including RS256 JWTs. / ECDSAElliptic Curve Digital Signature Algorithm — an asymmetric signing algorithm that achieves RSA-equivalent security with much smaller keys, at the cost of slightly slower signature verification.): a private key signs, a mathematically related but different public key verifies. Enables a fundamentally different trust boundary — third parties (a mobile app, a partner company, an open-source library) can verify a token's authenticity without ever holding the power to forge one.
Symmetric vs Asymmetric — The Real Engineering Trade-off
Symmetric (HMAC)
- One shared secret signs and verifies
- Extremely fast — microsecond-scale verification
- Anyone who can verify can also forge — unsuitable once a third party needs to verify
- Best fit: internal services, single-backend monoliths
Asymmetric (RSA / ECDSA)
- Private key signs, public key verifies — different keys, different powers
- Slower than HMAC, but still sub-millisecond
- Verifiers can never forge, even if the public key leaks — safe to distribute widely
- Best fit: OAuth/OIDC tokens, anything a third party must independently verify
•The Credential Lifecycle: Salting & Slow Hash Functions (bcrypt/Argon2)
The actual lifecycle: a user submits a plaintext password over TLS, the server generates a fresh random salt, runs the password and salt through a deliberately slow, memory-hard key derivation function (Argon2id or bcryptA deliberately slow, Blowfish-based password-hashing function, widely used because its cost factor can be tuned upward as hardware gets faster.), and persists only the resulting hash and salt — the plaintext itself is never stored, and ideally never even logged.
Memory-hardness matters for a specific reason beyond raw slowness: a purely CPU-slow hash, such as naively iterated SHA-256, can still be parallelized cheaply on GPUs and ASICs, which have thousands of inexpensive cores. A memory-hard function like Argon2The winner of the 2015 Password Hashing Competition — a memory-hard key derivation function that resists GPU and ASIC brute-force attacks far better than CPU-slow hashes alone. forces every parallel guess to allocate a large, non-shareable block of RAM, and RAM is expensive to parallelize at scale — that's what actually raises attacker cost by orders of magnitude, not the wall-clock delay alone.
A recurring real-world failure mode is rotating the hashing algorithm safely. Because the plaintext is never stored, a team can never simply 're-hash' every existing password when upgrading algorithms — the standard, subtle-but-correct approach is lazy migration: re-hash with the new algorithm the next time a given user successfully authenticates with their existing password, rather than attempting any kind of bulk migration.
Layer 1: Stateful Authentication — Sessions & Cookies
•Stateful Authentication — Sessions & Cookies
Stateful, session-based authentication is the original and still-dominant pattern for traditional server-rendered web applications: the server does the remembering, and the browser just carries a small, opaque pointer back on every request.
The Anatomy of a Session-Based System
Session Store
- In-memory (single server)
- Redis / Memcached (shared)
- Database-backed (durable, slower)
Session Identifier
- Cryptographically random ID
- Opaque — carries no data itself
- Typically 128+ bits of entropy
Delivery Mechanism
- HTTP Cookie (HttpOnly)
- Automatically resent by browser
- Never accessible to JavaScript
Lifecycle Controls
- Expiry / idle timeout
- Server-side revocation (delete record)
- Regeneration on privilege change
•The Session Lifecycle & Server-Side Session Stores
The full lifecycle, end to end: a successful login triggers the server to generate a random session ID, store a record such as { sessionId: { userId, createdAt, expiresAt, metadata } } in its session store, and set that ID as an HttpOnly cookie in the response. The browser then automatically resends the cookie on every subsequent request, and the server looks up the ID each time to reconstitute exactly who is making the request.
- In-memory session stores are the simplest but don't scale horizontally — a session created on Server A is invisible to Server B, breaking the moment more than one server instance runs without sticky routing.
- Shared session stores (Redis, Memcached) solve horizontal scaling by centralizing session state — every server instance reads and writes the same store, at the cost of a network round-trip on every request and a new single point of failure if that store goes down.
- Database-backed sessions trade speed for durability and auditability — slower than Redis, but sessions survive a cache flush and can be queried or audited directly, a trade-off some regulated industries require.
•Cookies as the Delivery Mechanism: Attributes, SameSite & CSRF
The cookie itself is "dumb" — it's the browser's built-in auto-resend behavior that makes it useful for sessions in the first place. That exact same behavior is also the root of CSRFCross-Site Request Forgery — an attack that tricks a logged-in user's browser into making an unwanted request to a site it's authenticated with, exploiting cookies the browser sends automatically., because the browser will attach the cookie to a request even when a malicious third-party site tricked the user's browser into making that request.
- HttpOnly prevents JavaScript — including injected XSSCross-Site Scripting — injecting malicious JavaScript into a page so it runs in a victim's browser with that page's own privileges, including the ability to read anything not protected by HttpOnly. payloads — from ever reading the cookie's value, the single most important defense against session theft via a compromised frontend script.
- Secure ensures the cookie is only ever sent over HTTPS, never in plaintext over an unencrypted connection.
- SameSite (Strict / Lax / None) controls whether the cookie is sent on cross-site requests at all — SameSite=Strict is the strongest CSRF defense, since the browser simply won't attach the session cookie to a request originating from a different site.
Set-Cookie: session_id=8f3a1c9b2e7d4f6a; HttpOnly; Secure; SameSite=Strict; Max-Age=3600; Path=/
•Session Fixation & Hijacking: The Attack Surface of Stateful Auth
Fixation and hijacking are the two dominant attack classes specific to stateful sessions — fixation plants a known session ID before login, hijacking steals a valid session ID after login — both exploiting the fact that the session ID alone, without any further proof, is the entire credential for the rest of that session's lifetime.
- Session FixationAn attack where the attacker sets a victim's session ID before login, then reuses that same known ID after the victim authenticates — defended by regenerating the session ID on every login.: an attacker tricks a victim into authenticating under a session ID the attacker already knows (e.g. via a crafted link), then reuses that same ID post-login — defended by always regenerating the session ID immediately after a successful authentication, never reusing a pre-login ID.
- Session Hijacking via Network Sniffing: intercepting an unencrypted session cookie in transit — effectively eliminated by enforcing HTTPS everywhere and the Secure cookie attribute.
- Session Hijacking via XSS: a malicious script reads the session cookie directly — defended primarily by HttpOnly, which removes the cookie from JavaScript's reach entirely, regardless of how the XSS payload got there.
- Session Hijacking via Physical/Shared Devices: a session left active on a shared or public computer — defended by short idle-timeout expiry and an explicit, working logout that actually deletes the server-side session record, not just clears a client-side cookie.
•Sessions at Scale: Redis-Backed Stores vs Sticky Sessions
There are two competing strategies for scaling stateful sessions across multiple servers: sticky sessions, where a load balancer always routes the same client to the same server instance so that server's local in-memory session remains valid, versus a shared external store, where any server instance can serve any request because session state lives centrally in Redis.
The honest trade-off: sticky sessions avoid the network round-trip cost of a shared store but create operational fragility — losing that one server instance, whether from a deploy, a crash, or an autoscale-down event, silently logs out every user pinned to it. A shared Redis store decouples session survival from any single server's lifecycle, at the cost of Redis itself becoming a new dependency that must be made highly available.
Shared Session Store: Any Server Can Serve Any Request
Server A
Server B
Server C
Redis Session Store
Single source of truth
•Stateful Auth Decision Matrix
| Requirement | Best Fit | Why |
|---|---|---|
| Traditional server-rendered web app | Server-side sessions + cookies | Simplest revocation model — delete the server-side record and access ends immediately |
| Need instant, guaranteed revocation (e.g. banking logout) | Server-side sessions | A session lookup happens on every request — revoke once, effective everywhere instantly |
| Multiple independent frontend clients (mobile + web + partner apps) | Stateless tokens (see Layer 2) | No shared session store dependency across completely separate client codebases |
| Horizontally scaling to many stateless backend instances with zero shared state | Stateless tokens (see Layer 2) | Sessions require either sticky routing or a shared store — tokens require neither |
| Regulated environment requiring session audit trail | Database-backed sessions | Every session is a queryable, durable record, not just an ephemeral cache entry |
Layer 2: Stateless Authentication — Tokens & JWTs
•Stateless Authentication — Tokens & JWTs
Instead of the server remembering anything, the proof of authentication is packed entirely into a self-contained, cryptographically signed object the client carries and presents on every request — the server verifies the signature instead of performing a lookup, trading a storage problem for a cryptography problem.
Stateless Token Flow
Client authenticates once
Client stores the token
Server verifies signature — no lookup needed
•JWT Anatomy: Header, Payload, Signature
A JWT is three base64url-encoded, dot-separated parts: the Header (algorithm and token-type metadata), the Payload (the claims — the actual data, such as the subject/user ID, issued-at time, expiry, and custom roles or permissions), and the Signature (a cryptographic proof over the header and payload, computed with either a shared secret or a private key).
The payload is encoded, not encrypted — anyone holding the token can decode and read every claim in plaintext. The signature only proves the claims haven't been tampered with since signing; it does not hide them. This single misunderstanding is behind a large share of real-world JWT misuse, such as storing secrets, PII, or authorization decisions that shouldn't be client-visible directly in the payload.
- 'sub' (subject) — the stable identifier for who this token represents, typically a user ID.
- 'exp' (expiry) — a Unix timestamp after which the token must be rejected, regardless of signature validity; this is the entire mechanism by which a stateless token eventually stops working.
- 'iat' / 'nbf' (issued-at / not-before) — timestamps bounding when the token becomes and stops being valid, used to reject tokens issued suspiciously in the future or replayed long after expected use.
Anatomy of a JWT
Header
alg, typ
Payload
sub, exp, iat, custom claims — readable by anyone
Signature
HMAC or RSA/ECDSA over header+payload
•Signing Algorithms: HS256 vs RS256 vs ES256
The practical decision rule: use HS256 (HMAC) when the same single backend both issues and verifies every token, since a shared secret is fine when there's exactly one trusted party. Switch to RS256 (RSA) or ES256 (ECDSA) the moment any other party — a separate microservice, a mobile app, a third-party API consumer — needs to verify tokens without being trusted to also issue them, since asymmetric signing lets the public verification key be published freely while the signing key stays locked to one issuer. One frequently-missed detail from the earlier timing table: RS256 tokens verify faster than ES256 despite ES256 having smaller keys, which is why many high-throughput public APIs still default to RS256 specifically for its cheaper, more frequent verification cost, accepting a larger token and key size as the trade-off.
•Access Tokens vs Refresh Tokens: The Rotation Problem
Systems split into two tokens instead of one to balance a security benefit against a UX cost: a short-lived access token, presented on every API call and cheap to let leak because it expires fast, paired with a long-lived refresh token, presented rarely and used only to mint new access tokens — avoiding the alternative of forcing a full re-login every few minutes.
Refresh token rotation is the current best practice: each time a refresh token is used, the server issues a brand new refresh token and invalidates the old one, effectively making refresh tokens single-use. A stolen-and-replayed old refresh token then immediately signals theft, because the legitimate client's next attempt to use it will fail, revealing the compromise.
- Access tokens should be short-lived (minutes) and never persisted to disk — kept only in memory, so a page reload or app restart naturally discards them.
- Refresh tokens should be long-lived but tightly scoped — usable only against the token endpoint, never against any actual API resource directly.
- Refresh token rotation converts a stolen token into a detectable event — reuse of an already-rotated-out refresh token is a strong signal of compromise, and a well-built system should revoke the entire token family on detecting it.
- Storing refresh tokens in an HttpOnly cookie, rather than local storage or app memory, reintroduces some of Layer 1's cookie protections — SameSite, HttpOnly — onto an otherwise stateless architecture, a hybrid pattern increasingly common in modern SPA and mobile backends.
•The Revocation Problem: Why Stateless Tokens Can't Really Be Revoked
A stateless token is valid purely because its signature checks out — the server verifying it never performs a lookup, which is the entire point of statelessness. That means there is no single place to "delete" a token the way a session record can be deleted; a leaked JWT remains fully valid to anyone holding it until its 'exp' timestamp arrives, no matter what the issuing server does after the fact.
This becomes a genuine incident-response problem: if an access token is leaked — browser extension malware, log exposure, a misconfigured proxy — the only guaranteed way to stop it is to wait out its expiry. That's exactly why the industry converged on deliberately short access-token lifetimes, typically 5–15 minutes, as damage-limitation, accepting more frequent refresh-token round-trips as the cost of bounding an attacker's usable window.
•Blocklists & Short-Lived Access Tokens
Some systems maintain a small, fast-lookup blocklist — checked on every request, typically in Redis — of explicitly revoked token IDs (a 'jti' claim) for the remaining duration of their natural lifetime. This hybrid approach reintroduces exactly the lookup cost stateless tokens were meant to avoid, but only for a tiny, bounded set of explicitly revoked tokens rather than every token ever issued, and only for the short remaining window until natural expiry.
Blocklist: Reintroducing a Lookup, But Only for the Exceptions
Token presented
Redis Blocklist
Only explicitly revoked tokens, until their natural exp
Proceed statelessly
•API Keys & Service-to-Service Auth: mTLS & Signed Requests
Service-to-service auth is a different problem from user auth — there's no human typing a password, no session UX to preserve, and both parties are often machines that can hold long-lived secrets securely. That opens mechanisms — raw API keys, mutual TLS, signed requests — that would be inappropriate for end users but are the right fit machine-to-machine.
| Mechanism | How It Works | Best Fit |
|---|---|---|
| Static API Key | A long-lived secret string sent in a header | Simple internal tools, low-stakes third-party integrations |
| HMAC-Signed Requests | Each request is signed with a shared secret over its own contents (path, timestamp, body) | Public APIs needing tamper-evidence without a full TLS client-cert setup — e.g. webhook verification |
| Mutual TLS (mTLS) | Both client and server present certificates and verify each other during the TLS handshake itself | High-security service meshes, financial/payment infrastructure, zero-trust internal networks |
| OAuth 2.0 Client Credentials Grant | A service authenticates with its own client ID/secret to get a short-lived access token | Service-to-service calls that should still flow through the same OAuth infrastructure as user-facing tokens |
•Specialized Tokens: PASETO, Macaroons & Biscuit
PASETOPlatform-Agnostic Security Tokens — a token format designed as a safer alternative to JWT by removing algorithm choice from the token itself, closing an entire class of algorithm-confusion attacks. (Platform-Agnostic Security Tokens) removes the notorious "alg" header confusion attack class by eliminating algorithm choice from the token format entirely — a token version dictates its algorithm, so there is no field an attacker can manipulate to downgrade or confuse verification.
Macaroons and Biscuit solve a different problem — delegatable, attenuable authorization: a holder can cryptographically append new restrictions to a token they already have, such as "this token, but only valid for read access, and only for the next 5 minutes," without contacting the original issuer at all. This is useful for capability-based systems where a token needs to be safely handed off to a less-trusted downstream service with strictly reduced power.
Layer 3: Federated & Passwordless Identity
•Federated & Passwordless Identity
Federation answers a specific scaling problem neither sessions nor raw tokens solve alone: how does a user prove their identity to Service B when they only ever created an account with Service A, without Service A and Service B sharing a database, and without the user creating and remembering yet another password.
| Standard | Answers The Question | Primary Use Case |
|---|---|---|
| OAuth 2.0 | Can this app access data on my behalf? | Delegated authorization — 'let this app read my calendar' |
| OpenID Connect (OIDC) | Who is this person, according to a trusted identity provider? | Authentication built on top of OAuth 2.0 — 'Sign in with Google' |
| SAML | Who is this person, for enterprise systems? | Enterprise SSO — logging into internal corporate tools via a company identity provider |
| WebAuthn / Passkeys | Does this device hold the private key it claims to? | Passwordless authentication, phishing-resistant by construction |
•OAuth 2.0: The Authorization Code Flow with PKCE
The flow, step by step: a user clicks "Sign in with Google," gets redirected to Google's own login page — never the client app's — authenticates directly with Google, and is redirected back to the client app with a short-lived authorization code. The client app's backend then exchanges that code, server-to-server, for an access token.
The redirect and code exist for a specific reason: the redirect ensures the client app's own frontend code never sees the user's actual Google credentials, and the code-for-token exchange happens server-to-server specifically so the long-lived access token never transits through the browser's URL bar or history, where it would be exposed to logging, referrer leaks, and browser extensions.
PKCEProof Key for Code Exchange — an OAuth 2.0 extension that binds an authorization code to the specific client that requested it, preventing a different app on the same device from intercepting and redeeming it. (Proof Key for Code Exchange) fixes a real historical vulnerability: without it, a malicious app on the same device could intercept the authorization code mid-flow and redeem it itself. PKCE has the client generate a secret "code verifier" upfront, send only its hash — the "code challenge" — in the initial redirect, and later prove possession of the original verifier during the token exchange, so an intercepted code alone is useless without the verifier only the legitimate initiating app ever held.
•OAuth vs OIDC vs SAML: Authorization vs Authentication vs Enterprise SSO
| OAuth 2.0 | OpenID Connect | SAML | |
|---|---|---|---|
| Primary Purpose | Delegated authorization (access, not identity) | Authentication, built atop OAuth 2.0 | Enterprise authentication & SSO |
| Token Format | Opaque access token (no fixed format) | ID Token — a signed JWT with identity claims | XML-based SAML assertion |
| Typical Era / Users | Consumer 'connect this app' flows | Modern consumer & B2B 'Sign in with X' | Legacy & large-enterprise identity systems |
| Answers | "What can this app do on my behalf?" | "Who is this person?" | "Who is this person, per corporate directory?" |
•The Risk of Federated Identity: SSO Outages & Single Points of Failure
Federating identity to a single provider — Google, Microsoft, Okta — removes password-management burden and improves security on average, but it also means that provider's availability becomes a hard dependency for every single downstream service relying on it. An outage at the identity provider doesn't just take down one service; it can simultaneously lock users out of every service that federates through it.
One Identity Provider Outage, Many Downstream Failures
Identity Provider
e.g. a major SSO/OIDC provider
Service A
Service B
Service C
•Passkeys & WebAuthn: The Passwordless Future
WebAuthn has the device, not the server, generate a public/private key pair at registration time — the private key never leaves the device's secure hardware, such as a TPM or Secure Enclave, and only the public key is ever sent to and stored by the server.
This is structurally phishing-resistant in a way passwords and even OTP/MFAMulti-Factor Authentication — requiring proof from more than one category of factor (something you know, have, or are) before granting access. codes are not: a PasskeyA WebAuthn credential — a public/private key pair generated and stored on a user's device, used to sign in without ever transmitting a shared secret a phishing site could steal. is cryptographically bound to the exact origin it was registered for, so a convincing fake login page on a look-alike domain simply cannot trigger the browser to release a signature. There is no secret the user can be tricked into typing into the wrong place, because there was never a shared secret to begin with.
- Device-bound by default — a passkey created on one phone doesn't automatically work on a laptop unless synced through a platform ecosystem (iCloud Keychain, Google Password Manager) or a physical roaming authenticator.
- Account recovery becomes the new hard problem — losing every device holding a passkey with no backup mechanism means losing access entirely, pushing the security challenge from 'protect a secret' to 'design a recovery flow that's convenient without becoming a new phishing target itself.'
- Adoption is happening at the platform layer, not the protocol layer — the cryptography has been stable for years; what changed recently is Apple, Google, and Microsoft building first-class passkey UX directly into their operating systems.
Industry Problems & Engineering Bottlenecks
•Credential Stuffing & Password Reuse at Scale
Attackers don't guess passwords one at a time against your system — they take a breach dump of billions of real email/password pairs stolen from an entirely different company, and replay those exact same pairs against your login endpoint at scale, betting correctly that a meaningful percentage of users reused the same password across services.
Credential Stuffing Doesn't Touch Your System's Crypto
Unrelated Company's Breach
Billions of real email:password pairs leaked
Your Login Endpoint
Successful Account Takeovers
IF login_attempts_for_ip > 20 in 60sOR distinct_usernames_from_ip > 10 in 60sTHEN require_captcha_or_block
•Session/Token Theft via XSS & Malicious Extensions
Regardless of whether an architecture uses sessions or JWTs, the credential ultimately lives somewhere accessible to client-side JavaScript unless deliberately locked down — a single successful XSS injection, or a single malicious browser extension with broad page-access permissions, can read and exfiltrate it just as effectively as a password.
- Tokens stored in localStorage or app memory — common for SPA/mobile JWT patterns — are directly readable by any JavaScript running on the page, including injected XSS payloads and over-permissioned browser extensions, with no platform-level barrier.
- Tokens or session IDs stored in HttpOnly cookies are invisible to JavaScript entirely, closing this specific theft vector — the recurring, non-obvious argument for why some teams deliberately choose cookie-based delivery even for otherwise-stateless JWTs.
•Phishing-Resistant Auth & the MFA Fatigue Attack
Traditional MFA — SMS codes, push-notification approvals — raised the bar against simple credential theft, but introduced a new, purely social attack: MFA fatigue, where an attacker who already has a stolen password simply triggers dozens of push notifications in a row, betting the legitimate user will eventually tap "Approve" out of annoyance, confusion, or assuming it's a glitch.
This class of attack is structurally impossible against WebAuthn and passkeys specifically, not just harder — there is no approval prompt an attacker can spam, because there is no separate secret or code being verified at all. The cryptographic challenge-response only ever succeeds if the physical device holding the private key is present and its origin check passes, so there's nothing for repeated attempts to wear down.
•Identity Provider Lock-In: The "Login with Google" Dependency
There's a business-continuity risk beyond the outage risk covered earlier: once "Sign in with Google" becomes a user's only way into an account, with no password ever set as a fallback, losing access to that Google account for any reason — a suspension, a forgotten recovery method, a policy dispute — permanently locks the user out of every downstream service too, with the downstream service having no independent way to verify or restore that user's identity.
One Suspended Account, Cascading Lockout
User's Google Account Suspended
Service A: Locked Out
Service B: Locked Out
Service C: Locked Out
•AI Agents & Machine Identity: Authenticating Non-Human Actors
The classic authentication model assumes a human is present to type a password, tap a passkey, or approve an MFA push — but an increasing share of "logins" today are autonomous AI agents acting on a user's behalf, booking a flight, calling an API, orchestrating other services, with no human present at the moment of the request to perform any of the traditional proof steps.
Two competing approaches are emerging: scoped, short-lived delegated tokens, where a human authenticates once and issues the agent a narrowly-scoped, time-boxed token — read-only, expires in ten minutes, this API only — rather than the agent ever holding the human's real credentials; and verifiable agent identity, where the agent itself holds its own cryptographic identity, similar to service-to-service mTLSMutual TLS — a TLS handshake where both the client and the server present and verify certificates, so each side authenticates the other, not just the server., and systems authorize based on which specific agent is acting plus what human or session originally delegated to it. This remains an area actively being standardized industry-wide as of 2026.
•Compliance, Privacy & Cross-Border Identity Data
Identity data is often the most sensitive category of personal data a system holds — not just credentials, but biometric templates from passkey/WebAuthn hardware attestation in some configurations, and third-party identity-provider profile data pulled in via OIDC. Different jurisdictions impose very different, sometimes conflicting rules on how that data can be stored, processed, and moved across borders.
- GDPRGeneral Data Protection Regulation — the EU's data-protection law, which includes the Right to Be Forgotten among its requirements.Learn more (EU) and similar regimes treat biometric and precise identity data as a special, higher-protection category, often requiring explicit consent and stricter breach-notification timelines than ordinary account data.
- Federating login through a foreign identity provider can itself become a data-sovereignty question — every authentication event may involve that provider's servers, which may sit in a different legal jurisdiction than either the user or the service they're logging into.
Decision Framework: Real-World Scenarios
•Scenario A: Consumer Mobile Banking App
Financial data, heavy regulatory scrutiny, and a strong expectation of both security and a fast, low-friction login on a device the user already trusts.
- Passkeys as the primary login method — phishing-resistant by construction, and mobile OS-level biometric hardware (Face ID, fingerprint) is already present and expected by users of a banking app.
- Short-lived access tokens (5–15 min) with rotating refresh tokens stored in secure device storage (Keychain/Keystore), never in a plain app-readable file.
- Step-up re-authentication for high-risk actions — a large transfer, adding a new payee — treating 'logged in' as insufficient authorization for the most sensitive actions, requiring a fresh biometric check at the moment of the action itself.
- Server-side session/token binding to device fingerprint signals, so a stolen token replayed from an unrecognized device pattern can be flagged and challenged even before its natural expiry.
Layered Auth for a Banking App
Passkey Login
Normal App Usage
Fresh Biometric Re-check Required
•Scenario B: High-Traffic Social Media Platform
Massive horizontal scale, many independent client types — web, iOS, Android, third-party API partners — and login friction directly costing signups and engagement.
- Stateless JWTs (RS256/ES256) as the default — the sheer number of backend instances and client types makes a shared session store an unnecessary bottleneck when tokens can be verified independently everywhere.
- "Sign in with X" (OIDC) offered prominently alongside a native option — lowering signup friction is a direct growth metric at this scale, and most users already have a Google or Apple account.
- Rate-limiting and Credential StuffingAutomated login attempts using real username/password pairs leaked from an unrelated breach, betting on password reuse across services. defenses tuned aggressively at the login endpoint specifically, since a platform this size is a constant, ongoing target for stuffing attacks using breach dumps from elsewhere.
Auth at Social-Media Scale
Web
iOS
Android
Partner API
No shared session store bottleneck
•Scenario C: B2B SaaS with Enterprise SSO
Enterprise buyers require the product to plug into their own existing corporate identity system, not the vendor's — the sale often depends on it contractually.
- SAML and/or OIDC support for enterprise SSOSingle Sign-On — authenticating once with a central identity provider and being automatically trusted by every other connected service, without logging in again for each one., since large customers already run their own identity provider (Okta, Azure AD, Google Workspace) and expect every vendor tool to federate into it, not maintain a separate password.
- SCIMSystem for Cross-domain Identity Management — a standard for automatically provisioning and deprovisioning user accounts across systems when they're added or removed in a central directory. (System for Cross-domain Identity Management) support for automated user provisioning and deprovisioning — when an employee is offboarded in the customer's own identity system, access to your product should be revoked automatically, without a manual support ticket.
- Per-tenant identity provider configuration — a true multi-tenant SaaS needs to federate with a different customer's identity provider per organization, not a single hardcoded OIDC config for the whole product.
- Role mapping from the customer's own directory groups into the product's internal permission model, so authorization decisions inherit the customer's existing org structure rather than requiring it to be manually recreated inside your product.
Multi-Tenant Enterprise SSO
Customer A's Okta
Customer B's Azure AD
Your SaaS Platform
•Scenario D: AI Agent / LLM Tool-Calling System
An LLM-based agent needs to call real APIs — calendars, email, payment systems — on a user's behalf, autonomously and without a human present at each individual call, while never being trusted with the user's actual root credentials.
- Scoped, short-lived delegated tokens issued once by the human — the agent receives a narrow capability, not the user's real session or password, bounding the damage of a compromised or misbehaving agent.
- Human-in-the-loop confirmation for irreversible or high-stakes actions — an actual payment, a public post, a delete — even when the agent otherwise operates autonomously, mirroring the step-up re-authentication pattern from the banking scenario.
- Full action-level audit logging tied to both the delegating human and the specific agent or session that acted — essential for after-the-fact review when an autonomous agent's action is disputed.
Delegated Agent Authority
Human authenticates once
AI Agent
Downstream APIs
•Scenario E: IoT Device Fleet Authentication
Thousands to millions of constrained, often-unattended devices, with no human present to type anything, and physical device compromise — someone stealing or tampering with a device — as a first-class threat model unique to this scenario.
- Per-device X.509 certificates provisioned at manufacture time, with mutual TLS for every device-to-cloud connection — there is no username/password concept at all; the device's identity is its certificate.
- Hardware-backed key storage — a secure element or TPM on the device — so the private key can't be extracted even with physical access to a stolen device.
- Certificate rotation and fleet-wide revocation lists sized for the realistic scale — a compromised device model or firmware batch needs to be revocable en masse, not one device at a time.
Device Identity, Not User Identity
Device Certificate (provisioned at manufacture)
Cloud IoT Gateway
Comparative Summary Matrix
•Comparative Summary Matrix
| Mechanism | State | Revocation | Best Fit | Key Weakness |
|---|---|---|---|---|
| Server-Side Sessions | Stateful | Instant (delete record) | Server-rendered web apps | Requires shared store or sticky routing to scale |
| JWT (Stateless) | Stateless | Only via expiry (or a blocklist hybrid) | Multi-client, horizontally scaled backends | Can't be truly revoked before expiry |
| OAuth 2.0 / OIDC | Federated | Depends on issuer's own token lifetime | Delegated access & 'Sign in with X' | Creates a hard dependency on the identity provider's uptime |
| SAML | Federated (enterprise) | Depends on IdP session | Enterprise SSO | Heavier, XML-based, legacy tooling |
| Passkeys / WebAuthn | Possession-based | Per-device revocation | Phishing-resistant consumer & enterprise login | Device loss/recovery UX still maturing |
| API Keys / mTLS | Machine-to-machine | Manual key/cert rotation | Service-to-service, IoT | No human-friendly UX — not for end users |
•Conclusion: Engineering for Layered Trust
There is no single "correct" authentication mechanism, exactly as there was no single correct storage engine — sessions, tokens, federation, and passkeys each trade differently across statefulness, revocability, scalability, and phishing-resistance, and a mature system often uses several simultaneously for different parts of itself: passkeys for human login, short-lived JWTs for API calls, mTLS for internal services.
Every mechanism covered here is really just a different answer to the same question this piece opened with: how much do you trust the claim in front of you right now, and how expensive was it, cryptographically, for someone to fake that claim. Good authentication architecture isn't about picking the "most secure" option in isolation — it's about matching each of the four concerns from the opening chapter to the mechanism whose trade-offs actually fit the system being built.
