Security
OAuth/OIDC: build and audit a hardened login
Reading about OAuth CVEs is not the same as proving your own implementation has none. Build a small but complete OIDC login against a real authorization server, sender-constrain the API, then attack each mandatory check yourself — only an adversarial test that fails on the broken path proves the check is actually there.
Turn the unit’s complete-set model into a working, audited system: authorization code with PKCE, full id_token validation with JWKS rotation handling, refresh rotation with replay detection, DPoP-bound API calls, and an observability dashboard — each defended by a test that proves the check holds.
Build a hardened OIDC login and a sender-constrained protected API against a real authorization server (Auth0, Okta, Keycloak, or Authentik), then run a security audit that proves every mandatory check with an adversarial test that the unhardened path would fail.
- An adversarial test suite where each test exercises one broken path and is rejected: a replayed authorization code (PKCE), a mismatched state, a tampered or alg=none id_token, an id_token with the wrong aud, a reused refresh token (replay detection fires), and a DPoP call with a missing or wrong proof.
- A demonstrated JWKS key-rotation scenario: rotate the IdP signing key (or simulate a new kid) and show login keeps working because on-cache-miss refresh fetches the new key instead of 401-ing.
- A token-storage check: the access token is provably absent from localStorage and the refresh token is in an httpOnly cookie inaccessible to JS (or the platform equivalent).
- The dashboard shows refresh_replay_detected_total incrementing exactly once when the reused-refresh-token test runs, and id_token_validation_failure_total incrementing by reason for each rejected id_token test.
- A one-page audit write-up mapping each of the unit's mandatory checks (PKCE, exact redirect, eight id_token checks, refresh rotation, sender-constraint, audience validation) to the test that proves it.
- Add PAR (Pushed Authorization Requests) so authorize parameters never appear in the browser URL, and show they are absent from history and referrer headers.
- Add token introspection on a high-sensitivity write endpoint with a 30s introspection cache, and demonstrate that a token revoked at the IdP is rejected within the cache window while local JWT validation still serves the read path.
- Add RFC 8707 Resource Indicators so a token minted for API-A is rejected by API-B, and include the regression test that an aud set to other-api is refused.
- Run the same login against a second authorization server (e.g. swap Keycloak for Auth0) and document which checks needed configuration changes and which were portable.
This is the loop you run on every real OAuth integration: build the flow with PKCE, validate the id_token completely with a pinned algorithm and on-cache-miss JWKS refresh, rotate refresh tokens with replay detection, sender-constrain the API with DPoP, store tokens by client threat model, and wire the observability that surfaces compromise. Then audit it adversarially — a check you have not attacked is a check you have not proven. Doing this once on a small system turns the complete-set discipline into muscle memory for production.