📝 docs: ADR-0028 Phase B roadmap (B.3 / B.4 / B.5 outline) (#71)
Co-authored-by: Gabriel Radureau <arcodange@gmail.com> Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
This commit was merged in pull request #71.
This commit is contained in:
137
documentation/PHASE_B_ROADMAP.md
Normal file
137
documentation/PHASE_B_ROADMAP.md
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
# ADR-0028 Phase B Roadmap
|
||||||
|
|
||||||
|
**Document ID:** PHASE_B_ROADMAP
|
||||||
|
**Date:** 2026-05-05 evening
|
||||||
|
**Status:** In Progress
|
||||||
|
**Author:** AI Agent (vibe/batch4-task-b-phase-b-roadmap)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Status as of 2026-05-05 evening
|
||||||
|
|
||||||
|
- [x] ADR-0028 Phase A complete (PRs #59-#63, #65)
|
||||||
|
- [x] Phase B.1 OIDC config (PR #64)
|
||||||
|
- [x] Phase B prep : pkg/auth skeleton (PR #69) + mkcert doc (PR #68)
|
||||||
|
- [ ] Phase B.3 not yet started
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Remaining work
|
||||||
|
|
||||||
|
Phase B delivers OpenID Connect Authorization Code flow with PKCE. Work is organized into **3 shippable phases**, each deliverable as an independent PR.
|
||||||
|
|
||||||
|
### Phase B.3 — OIDC client implementation
|
||||||
|
- **Goal:** Implement the core OIDC client methods in `pkg/auth/oidc.go`
|
||||||
|
- **Tasks:**
|
||||||
|
- `Discover()`: HTTP GET to `/.well-known/openid-configuration`, parse + cache discovery document
|
||||||
|
- `RefreshJWKS()`: HTTP GET to JWKS URI, parse RSA public keys, cache with TTL
|
||||||
|
- `ExchangeCode()`: POST to token endpoint with code + PKCE verifier, return TokenResponse
|
||||||
|
- `ValidateIDToken()`: Verify signature against JWKS, validate standard claims (iss, aud, exp, iat)
|
||||||
|
- **LOE:** ~200 lines of Go + unit tests
|
||||||
|
- **Dependencies:** None (uses standard library `crypto/rsa`, `encoding/jwt`)
|
||||||
|
- **Deliverable:** 1 PR
|
||||||
|
|
||||||
|
### Phase B.4 — OIDC HTTP handlers
|
||||||
|
- **Goal:** Add OIDC flow endpoints and wire them into the server
|
||||||
|
- **Tasks:**
|
||||||
|
- Create `pkg/user/api/oidc_handler.go`
|
||||||
|
- `GET /api/v1/auth/oidc/start`:
|
||||||
|
- Generate state (CSRF protection) + PKCE verifier + challenge
|
||||||
|
- Store state + verifier (cookie or short-lived in-memory store)
|
||||||
|
- Redirect to provider's authorization endpoint
|
||||||
|
- `GET /api/v1/auth/oidc/callback`:
|
||||||
|
- Validate state parameter matches stored state
|
||||||
|
- Exchange code for tokens (calls B.3 client)
|
||||||
|
- Validate id_token (calls B.3 client)
|
||||||
|
- Issue internal JWT (reuse existing JWT manager from ADR-0021)
|
||||||
|
- Return JWT in Set-Cookie + JSON body
|
||||||
|
- Wire routes in `pkg/server/server.go`
|
||||||
|
- **LOE:** ~150 lines of Go + unit tests + integration tests
|
||||||
|
- **Dependencies:** B.3 (client methods must be implemented)
|
||||||
|
- **Prerequisite:** Run `make cert` (mkcert, from PR #68) before starting dev
|
||||||
|
- **Deliverable:** 1 PR
|
||||||
|
|
||||||
|
### Phase B.5 — BDD coverage
|
||||||
|
- **Goal:** End-to-end OIDC testing
|
||||||
|
- **Tasks:**
|
||||||
|
- Create `features/auth/oidc.feature` with scenarios:
|
||||||
|
- Happy path: start → provider auth → callback → JWT issued
|
||||||
|
- Error: state mismatch
|
||||||
|
- Error: invalid code
|
||||||
|
- Error: expired id_token
|
||||||
|
- Use mock OIDC provider (local in-process) OR deterministic test against Authelia/Keycloak in docker-compose
|
||||||
|
- Follow ADR-0030 parallel BDD strategy for email assertions
|
||||||
|
- **LOE:** ~150 lines of Gherkin + step definitions
|
||||||
|
- **Dependencies:** B.3 + B.4 (endpoints must be operational)
|
||||||
|
- **Deliverable:** 1 PR
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dependencies and order
|
||||||
|
|
||||||
|
```
|
||||||
|
B.3 (OIDC client)
|
||||||
|
↓
|
||||||
|
B.4 (HTTP handlers) —— requires B.3
|
||||||
|
↓
|
||||||
|
B.5 (BDD coverage) —— requires B.3 + B.4
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** mkcert (PR #68) is ready. When starting B.4 development, run `make cert` once to generate local HTTPS certificates.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Out of scope for Phase B (deferred)
|
||||||
|
|
||||||
|
| Item | Target Phase | Rationale |
|
||||||
|
|------|--------------|-----------|
|
||||||
|
| Decommission password auth | Phase C | Separate ADR after B is in production |
|
||||||
|
| Multi-provider (Authelia + Google) | Phase B.6 (if needed) | Single provider sufficient for MVP |
|
||||||
|
| JWKS rotation mid-flight retry | B.3 enhancement | Handle in initial implementation |
|
||||||
|
| Token refresh flow | Future | Not required for auth code flow MVP |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Risk register
|
||||||
|
|
||||||
|
| Risk | Mitigation | Owner |
|
||||||
|
|------|------------|-------|
|
||||||
|
| JWKS rotation handling | Implement refresh + retry logic; key rotation must not break mid-flight validation | B.3 implementer |
|
||||||
|
| PKCE storage | Use signed cookie or short-lived in-memory store; document trade-offs in implementation PR | B.4 implementer |
|
||||||
|
| Testing without real provider | Use mock OIDC server for CI; local dev uses Authelia in docker-compose | B.5 implementer |
|
||||||
|
| State CSRF protection | Use cryptographically random state; store server-side with short TTL | B.4 implementer |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cross-references
|
||||||
|
|
||||||
|
- [ADR-0028: Passwordless authentication: magic link → OpenID Connect](../adr/0028-passwordless-auth-migration.md)
|
||||||
|
- [ADR-0029: Email infrastructure (Mailpit)](../adr/0029-email-infrastructure-mailpit.md)
|
||||||
|
- [ADR-0030: BDD email parallel strategy](../adr/0030-bdd-email-parallel-strategy.md)
|
||||||
|
- [PR #59: Email infrastructure](https://gitea.arcodange.lab/arcodange/dance-lessons-coach/pulls/59)
|
||||||
|
- [PR #60: BDD Mailpit helper](https://gitea.arcodange.lab/arcodange/dance-lessons-coach/pulls/60)
|
||||||
|
- [PR #61: magic_link_tokens table](https://gitea.arcodange.lab/arcodange/dance-lessons-coach/pulls/61)
|
||||||
|
- [PR #62: Magic link handlers](https://gitea.arcodange.lab/arcodange/dance-lessons-coach/pulls/62)
|
||||||
|
- [PR #63: Magic link BDD](https://gitea.arcodange.lab/arcodange/dance-lessons-coach/pulls/63)
|
||||||
|
- [PR #64: OIDC config skeleton](https://gitea.arcodange.lab/arcodange/dance-lessons-coach/pulls/64)
|
||||||
|
- [PR #65: Magic link cleanup loop](https://gitea.arcodange.lab/arcodange/dance-lessons-coach/pulls/65)
|
||||||
|
- [PR #68: mkcert documentation](https://gitea.arcodange.lab/arcodange/dance-lessons-coach/pulls/68)
|
||||||
|
- [PR #69: pkg/auth skeleton](https://gitea.arcodange.lab/arcodange/dance-lessons-coach/pulls/69)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Appendix: File inventory
|
||||||
|
|
||||||
|
Existing (merged):
|
||||||
|
- `pkg/auth/oidc.go` — skeleton with TODO methods (PR #69)
|
||||||
|
- `pkg/auth/oidc_test.go` — placeholder tests (PR #69)
|
||||||
|
- `documentation/MKCERT.md` — mkcert setup guide (PR #68)
|
||||||
|
- `Makefile` — includes `make cert` target (PR #68)
|
||||||
|
|
||||||
|
To be created:
|
||||||
|
- `pkg/auth/oidc.go` — complete implementation (B.3)
|
||||||
|
- `pkg/user/api/oidc_handler.go` — HTTP handlers (B.4)
|
||||||
|
- `pkg/server/server.go` — route wiring (B.4)
|
||||||
|
- `features/auth/oidc.feature` — BDD scenarios (B.5)
|
||||||
|
- `pkg/auth/oidc_test.go` — expanded unit tests (B.3)
|
||||||
|
- `pkg/user/api/oidc_handler_test.go` — handler tests (B.4)
|
||||||
Reference in New Issue
Block a user