3d487b82ef
Requirements completed: AUTH-01, AUTH-02, AUTH-04, SEC-01, SEC-02, SEC-03, SEC-05 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 KiB
13 KiB
phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, duration, completed
| phase | plan | subsystem | tags | requires | provides | affects | tech-stack | key-files | key-decisions | duration | completed | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 02-users-authentication | 02 | auth |
|
|
|
|
|
|
|
~60min | 2026-05-22 |
Phase 2 Plan 02: Auth API Endpoints and Frontend Auth Wall Summary
Auth API (register/login/refresh/logout/me/change-password) with per-account Redis rate limiting, Origin validation, CSP headers, CORS lockdown, and Vue 3 auth store + router guard + Login/Register views — full auth wall live
Performance
- Duration: ~60 min
- Started: 2026-05-22T17:30:00Z
- Completed: 2026-05-22T17:45:52Z
- Tasks: 2 (Task 1 TDD, Task 2 standard)
- Files created: 15, Files modified: 9
Accomplishments
- Full auth API endpoints in
backend/api/auth.py: register (HIBP + strength check), login (TOTP + backup code paths), refresh (token rotation), logout, logout-all, me, change-password - Security hardening in
backend/main.py: Origin validation middleware (403 on cross-origin non-GET), CSP headers (Content-Security-Policy, X-Frame-Options, X-Content-Type-Options), CORS locked tosettings.cors_origins(wildcard removed), Redis lifespan wiring, admin bootstrap - Per-account rate limiting: Redis counter
login_attempts:{email}capped at 10 in 15 min; IP-level slowapi10/minuteon register/login/refresh - httpOnly Secure SameSite=Strict refresh cookie on path=/api/auth/refresh (CLAUDE.md constraint)
- 17 TDD tests all passing: covers all endpoint behaviors including backup code issuance/invalidation, password_must_change flow, TOTP precedence over backup_code, Origin validation, and per-account rate limit
- Vue 3 auth store (
useAuthStore): accessToken inref()memory only — never localStorage/sessionStorage;login()acceptsoptions.backupCode - API client extended: Bearer token injection, 401 auto-refresh retry, full set of auth/admin exports including
changePassword - Router
beforeEachguard: redirects unauthenticated users to/login?redirect=<original-path> - Login view: three-step flow (password → TOTP → backup code); "Use a backup code instead" toggle; UI-SPEC copywriting
- Register view:
PasswordStrengthBarcomponent (4-segment, score 0-4), HIBP error inline AppSpinner.vue: lightweight animate-spin SVG inheriting button text colorAuthLayout.vue: centered bare layout with DocuVault brandnpm run buildexits 0
Task Commits
- Task 1 RED — test file:
1d425d4(test) - Task 1 GREEN — implementation:
1882edf(feat) - Task 2 — frontend:
3b7d362(feat)
Files Created/Modified
See key-files in frontmatter.
Decisions Made
- Middleware insertion order: SecurityHeaders first, CORS second, OriginValidation last — Starlette applies in reverse, so OriginValidation runs first on every request
- Per-account Redis counter: TTL set only on first
incr()call (count == 1) to ensure the 15-minute window starts from the first attempt, not the last - Dynamic import in client.js:
await import('../stores/auth.js')insiderequest()avoids the circular import between stores/auth → api/client → stores/auth - Slowapi storage reset in tests:
auth_limiter._storage.reset()called inauthed_clientfixture setup to prevent IP counters from one test bleeding into the next
Deviations from Plan
Auto-fixed Issues
1. [Rule 1 - Bug] Python 3.9 incompatibility: match statement in ai/__init__.py
- Found during: Task 1 (RED phase — test setup import chain)
- Issue:
ai/__init__.pyused Python 3.10matchstatement; failed with SyntaxError on Python 3.9 - Fix: Replaced
matchwithif/elifchain (equivalent behavior, Python 3.9 compatible) - Files modified:
backend/ai/__init__.py
2. [Rule 1 - Bug] Python 3.9 incompatibility: str | None union syntax in multiple files
- Found during: Task 1 (RED phase — test setup import chain)
- Issue:
str | Noneunion syntax requires Python 3.10+; FastAPI/Pydantic evaluate route annotations at runtime - Fix: Changed to
Optional[str]in all affected files; addedfrom __future__ import annotationsto classifier.py (annotation-only, no runtime evaluation) - Files modified:
backend/ai/openai_provider.py,backend/api/documents.py,backend/api/topics.py,backend/api/settings.py,backend/services/classifier.py - Note: This is a pre-existing issue in the codebase (also noted in 02-01 summary) that was blocking all tests
3. [Rule 1 - Bug] Slowapi IP-level counter bleed between tests
- Found during: Task 1 GREEN phase (test suite)
- Issue: 10 tests calling
/api/auth/registeror/api/auth/loginaccumulated against IP127.0.0.1, causingtest_per_account_rate_limitto fail when run in sequence (IP limit hit before per-account counter) - Fix: Added slowapi storage reset (
auth_limiter._storage.reset()) toauthed_clientfixture before each test - Files modified:
backend/tests/test_auth_api.py
4. [Rule 2 - Missing] email-validator package not installed locally
- Found during: Task 1 GREEN phase (import test)
- Issue: Pydantic
EmailStrrequiresemail-validatorpackage; not installed in local Python 3.9 env - Fix:
pip install 'pydantic[email]'locally (already in requirements for Docker env) - Note: No file changes needed; package is implicitly included via
pydantic[email]in Docker container
Known Stubs
AdminView.vue: tab navigation shell only — user/quota/AI config management deferred to Plan 02-03 (admin API endpoints)AccountView.vue: change-password and sign-out-all wired; TOTP enrollment UI deferred to Plan 02-04PasswordResetView.vue,NewPasswordView.vue: forms wired to API but password-reset confirm endpoint not yet implemented in backend (deferred to Plan 02-05)- None of these stubs prevent Plan 02's goal (auth wall live) from being achieved
Threat Flags
None — all new endpoints follow STRIDE threat model mitigations:
- T-02-09: Identical 401 message for non-existent email and wrong password (anti-enumeration)
- T-02-11: SameSite=Strict + Origin middleware for CSRF prevention
- T-02-13: Dual rate limiting (IP-level slowapi + per-account Redis)
- T-02-14: CSP, X-Frame-Options, X-Content-Type-Options on all responses
- T-02-15: CORS wildcard removed
- T-02-16: password_must_change=True returns 200 with flag only, no tokens
- T-02-26: verify_backup_code marks used_at on first use; constant-time comparison
- T-02-27: per-account rate limit applies to all login paths including backup code
Self-Check
See section below.
Self-Check: PASSED
Files verified:
- backend/api/auth.py — FOUND
- backend/main.py — contains
app.state.redis(FOUND),cors_origins(FOUND),Content-Security-Policy(FOUND) - backend/tests/test_auth_api.py — FOUND (17 tests, all passing)
- frontend/src/stores/auth.js — FOUND, no localStorage
- frontend/src/router/index.js — FOUND, contains beforeEach and /login
- frontend/src/layouts/AuthLayout.vue — FOUND
- frontend/src/views/auth/LoginView.vue — FOUND, contains "Sign in to DocuVault" and backupCode
- frontend/src/views/auth/RegisterView.vue — FOUND, contains "Create your account"
- frontend/src/components/auth/PasswordStrengthBar.vue — FOUND
- frontend/src/components/ui/AppSpinner.vue — FOUND, contains "animate-spin"
- frontend/src/api/client.js — FOUND, contains "Authorization", "Bearer", "_retry", "refresh", "changePassword"
Commits verified:
1d425d4(test: RED phase — test_auth_api.py) — FOUND1882edf(feat: GREEN phase — auth.py + main.py + Python 3.9 fixes) — FOUND3b7d362(feat: frontend auth store, router, views) — FOUND
Verification results:
- pytest tests/test_auth_api.py: 17 passed
- npm run build: exits 0
- grep -c allow_origins=["*"] backend/main.py: 0
- grep -c localStorage frontend/src/stores/auth.js: 0
- grep -c backup_code backend/api/auth.py: 7
Phase: 02-users-authentication Completed: 2026-05-22