Wave 10: task breakdown for the Okta OIDC build
This commit is contained in:
55
docs/waves/wave-10.md
Normal file
55
docs/waves/wave-10.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Wave 10 — Okta OIDC authentication
|
||||
|
||||
Fresh wave 10. The label was previously used by the LDAPS work under `D13`/`D14`, built on
|
||||
`feat/ldaps-directory-auth`; that branch was deleted rather than merged and never appeared
|
||||
in `IMPLEMENTATION.md`'s wave table, so it carries no claim on the number. See
|
||||
`docs/waves/decisions-2026-09-02.md` (`D15`) for why LDAPS was retired before deployment
|
||||
and Okta chosen instead.
|
||||
|
||||
Depends only on `main` as it stands after `D15`. Not sequenced behind any other wave.
|
||||
|
||||
## Tasks
|
||||
|
||||
- **T10.1 — Add the Okta OIDC client.** Authlib as a dependency. Config via env vars
|
||||
(`OKTA_ISSUER`, `OKTA_CLIENT_ID`, `OKTA_CLIENT_SECRET`, `OKTA_REDIRECT_URI`), same
|
||||
pattern `AUTH_SECRET_KEY` already uses in `server/auth.py`.
|
||||
|
||||
- **T10.2 — Login-redirect and callback routes.** A route that sends the browser to
|
||||
Okta's authorize endpoint, and a callback route that exchanges the code for tokens and
|
||||
validates the ID token. Access gating is Okta's job, not this app's: only accounts
|
||||
assigned to the app integration in Okta can reach it at all, so there is no app-side
|
||||
required-group or claim check layered on top. This is a deliberate difference from D13,
|
||||
which had to gate on a required AD group itself because an LDAPS bind alone could not
|
||||
distinguish an assigned user from any other domain account.
|
||||
|
||||
- **T10.3 — Identity matching and JIT provisioning.** Reuses D13's shape
|
||||
(`_provision_from_directory`-style matching) keyed off an OIDC claim instead of an LDAP
|
||||
search result. **Open dependency:** which claim carries the AD `sAMAccountName`
|
||||
equivalent (`preferred_username`, `upn`, or a custom claim) is asked of security and not
|
||||
yet answered. Build with a configurable claim name and a documented default, not a
|
||||
hardcoded one, so the answer can drop in without a code change.
|
||||
|
||||
- **T10.4 — Remove the local password path entirely.** Drop `password_hash`, remove the
|
||||
bcrypt-based `login()`, remove the username/password form. Real deletion, matching
|
||||
`D15`'s "full replacement," not a toggle or a fallback.
|
||||
|
||||
- **T10.5 — Frontend: login becomes a redirect, not a form.** `login.html`/`login.js`
|
||||
change to a "Sign in with Okta" flow. Sign-out lands back on the app's own login page.
|
||||
|
||||
- **T10.6 — Deployment docs and env var reference.** `DEPLOYMENT.md`,
|
||||
`server/.env.example`, `server/README.md` describe the Okta config in place of the LDAP
|
||||
config they never ended up describing (D13 never shipped, so these still describe the
|
||||
original local-password system today).
|
||||
|
||||
- **T10.7 — Test coverage without a live Okta dependency.** A fake-OIDC-provider test
|
||||
seam, mirroring `ldap_fake.py`, so the suite runs with no live Okta tenant reachable.
|
||||
|
||||
- **T10.8 — Verification.** 390px and 1440px, full suite, done-when checks per task,
|
||||
matching the rigor D13 was held to.
|
||||
|
||||
## Still open
|
||||
|
||||
- The OIDC claim mapping (`T10.3`).
|
||||
- Final confirmation of the redirect/callback URI (`https://wp.controls.dev/api/auth/okta/callback`
|
||||
proposed, pending security).
|
||||
- The `Business Technology Group` pilot assignment in Okta.
|
||||
Reference in New Issue
Block a user