Recovery and operations

Operate and test authentication

Monitor security events, review active sessions, rotate secrets, patch dependencies, test abuse cases, and prepare an incident response for credential or session compromise.

Shipping the login system is the start, not the end. Hashing recommendations change, providers rotate keys, a dependency gets a CVE, and attackers find your form the day it goes live. Authentication is a production system you operate.

Log decisions, never credentials

Good logs describe what the system decided. Useful events: login success and failure, a challenge or throttle kicking in, session creation and revocation, password reset, factor changes, and authorization denials.

Record stable internal identifiers and coarse context, a user ID and a country for instance. Never record passwords, raw session IDs, reset links, authorization codes, or recovery codes. A log full of session tokens is a second, weaker credential store.

Alert on a hypothesis

Don’t alert on “failed logins went up”. Alert on patterns that map to an attack from your threat model:

  • a burst of failures across many accounts suggests password spraying
  • many networks failing against one account suggests a targeted attack
  • a login from a new country followed by factor removal suggests a takeover in progress

Thresholds need tuning against real traffic. And support needs a screen that shows why a user got challenged, or every alert becomes a ticket.

Give users and admins control

Users should see their active sessions with a device name and last activity, and revoke one or all of them. That’s the most useful self-service security feature you can ship.

Administrators need an audited emergency path to revoke everything globally. Secret rotation needs overlap rules: introduce the new signing key, accept the old one for a bounded period, then remove it. Write the runbook with names in it.

Test properties, not happy paths

Endpoint tests that check 200 OK don’t catch authentication bugs. Test the properties. Compare responses for known and unknown accounts byte for byte. Replay a reset link and an OAuth callback. Race two token redemptions. Send a CSRF request to every cookie-authenticated mutation. Swap resource IDs between two users. Copy a session cookie into another browser. Then kill the session store and the email provider and watch.

That last one has a rule: when authority is uncertain, fail closed. But don’t overdo it, or a wobbly Redis instance locks every user out. Decide per route, and test it.

Two playbooks

Write two short incident playbooks before you need them. One for “the sessions table leaked”. One for “the OAuth client secret is on GitHub”. Each covers detection, containment, what you revoke, what you tell users, recovery, and the change that stops it happening again.

Try this on the Books API: draft both playbooks, one page each. Then turn the checks from this lesson into a release checklist with a team’s name at the top. A checklist nobody owns is a document nobody reads.

Lesson completed