Skip to content

Chapter 15 of 204 min readBy Deepak GuptaPublished

Infrastructure and Scaling

Authentication load is spiky, CPU-heavy at one point (password hashing), and nearly always on the critical path. Scale it by keeping compute stateless, protecting the hashing pool from abuse, and letting downstream services validate tokens without calling you.

Capacity math for password hashing

Password verification is deliberately expensive, so it sets your compute budget. Measure first, then size with a simple formula:

cores = (peak verifications per second x CPU seconds per hash) / target utilization

Illustrative example only, with numbers you must replace by your own benchmark: if one Argon2id verification at your parameters takes 50 ms of one core, a peak of 500 password sign-ins per second keeps 25 cores busy. At a 50% utilization target, provision 50 cores. Memory is about 25 concurrent hashes times 19 MiB, under 1 GiB.

Three rules follow:

  1. Rate-limit and risk-score before you hash. A credential-stuffing burst can be many times normal traffic. Reject obvious abuse at the edge and in cheap checks first, so attackers cannot buy your CPU.
  2. Isolate hashing. Run verification in a dedicated worker pool or service with its own autoscaling and queue limits, so a flood degrades sign-in, not the whole platform.
  3. Passkeys are cheap. Signature verification costs a tiny fraction of a slow hash. Every user you move to passkeys lowers your compute bill.

Data stores

Store Access pattern Typical choice
User store Read by identifier on every sign-in; writes on signup and changes Relational database with read replicas, one primary per region
Session cache Very high read rate, short TTLs In-memory key-value store with replication and persistence
Rate-limit counters Very high write rate, tiny values Same in-memory store, separate keyspace
Audit log Append-only, high volume, read during investigations Event stream into immutable object storage plus a searchable index

Index every lookup path: normalized identifier, credential ID, federated (provider, subject), and session hash. Never query users by email with a sequential scan, even once.

Keep the identity service off the hot path

  • Downstream APIs validate JWT access tokens locally against a cached JWKS. They should not call /introspect or /userinfo per request unless they use opaque tokens.
  • Product services read the session through a shared library or a gateway that caches it briefly, not through a synchronous call to the auth service on every request.

Multi-region

  1. Assign a home region per user at signup (Chapter 16). The user's records live there.
  2. Keep a minimal global routing index: a keyed hash of each normalized identifier mapped to the home region. It holds no personal data in readable form.
  3. Route sign-ins to the home region. Serve static login UI and JWKS from the edge everywhere.
  4. Fail over within a jurisdiction where law requires it (for example, between two EU regions), not across one.
  5. Replicate signing public keys everywhere; keep each region's private signing keys in that region's KMS, or use one issuer with region-specific keys and kid values.

Availability targets

If login is down, your whole product is down. Set a target per path and design degraded modes:

Dependency down Degraded behavior
Risk engine Fail toward step-up for new devices; allow known devices
Breached-password service Allow and re-check at next sign-in
Email or SMS provider Queue messages; offer passkey or TOTP instead
Enterprise IdP Show a clear tenant-specific error; never fall back to a weaker method silently
Primary database Serve existing sessions from cache; block new sign-ins in that region only

A 99.99% target allows about 52 minutes of downtime a year. Achieving it needs multi-zone deployment, zero-downtime migrations, and rehearsed failover, not just more servers.

Warning

Common mistakes

  • Hashing on the same thread pool that serves every other request.
  • Every API calling the auth service synchronously to validate each request.
  • Load tests that only test the happy path, never a credential-stuffing burst.

Key takeaways

  • Password hashing sets your compute budget; measure it, then size cores with a simple formula.
  • Rate-limit and risk-score before hashing, and isolate hashing in its own worker pool.
  • Let downstream APIs validate tokens locally against a cached JWKS.
  • Design a degraded mode for every dependency; 99.99% allows about 52 minutes of downtime a year.