feat(mvp): phase 3 - authentication system

Implement local auth flow: login, registration, logout, JWT access/refresh
tokens in HTTP-only cookies, hooks.server.ts middleware, guest mode support,
Superforms + Zod validation, and reusable auth/authorize middleware.
This commit is contained in:
2026-03-24 20:45:14 +03:00
parent f1b1aa5975
commit 2c001df322
19 changed files with 751 additions and 28 deletions
+2 -2
View File
@@ -2,7 +2,7 @@
## Current State
Phase 2 (Database Schema & Services Layer) is complete. The Prisma schema defines 10 models (User, Group, UserGroup, App, AppStatus, Board, Section, Widget, Permission, SystemSettings). Initial migration has been applied and the SQLite database created at `data/launcher.db`. Seed data includes an admin user, default groups, 5 sample apps, and a default board with 2 sections. Six server-side services provide full CRUD operations. Zod validators, TypeScript type definitions, shared constants, and an API response envelope utility are all in place. Build does not pass yet (Big Bang strategy — expected).
Phase 3 (Authentication System) is complete. The full local authentication flow is implemented: login, registration, logout, and JWT token refresh. `hooks.server.ts` validates access tokens on every request, injects `event.locals.user`/`session`, and silently rotates expired tokens via refresh tokens. Protected routes redirect to `/login`; guest-accessible board routes are exempt. Login and registration pages use Superforms + Zod with inline validation errors. Registration respects the `SystemSettings.registrationEnabled` toggle. Reusable middleware helpers (`requireAuth`, `requireAdmin`, `requireRole`) are available for downstream phases. The root layout injects user session into all page data. The root page redirects to the default board or login. `jwt.ts` and `password.ts` are thin re-exports from `authService` (no duplication). Build does not pass yet (Big Bang strategy — expected).
## Temporary Workarounds
@@ -13,7 +13,7 @@ Phase 2 (Database Schema & Services Layer) is complete. The Prisma schema define
## Cross-Phase Dependencies
- Phase 2 depends on Phase 1 (project scaffolding, Prisma setup)
- Phase 3 depends on Phase 2 (user/group models, auth service)
- Phase 3 depends on Phase 2 (user/group models, auth service)
- Phase 4 depends on Phase 2 (app model, services layer)
- Phase 5 depends on Phase 2 (board/section/widget models) and Phase 4 (app widget references apps)
- Phase 6 depends on Phases 3-5 (admin needs auth, app, board entities)
+2 -2
View File
@@ -29,7 +29,7 @@ Build a self-hosted web application launcher/dashboard for a TrueNAS server envi
- [x] Phase 1: Project Scaffolding & Tooling [backend] → [subplan](./phase-1-scaffolding.md)
- [x] Phase 2: Database Schema & Services Layer [backend] → [subplan](./phase-2-database-services.md)
- [ ] Phase 3: Authentication System [fullstack] → [subplan](./phase-3-authentication.md)
- [x] Phase 3: Authentication System [fullstack] → [subplan](./phase-3-authentication.md)
- [ ] Phase 4: App Registry & Healthcheck [fullstack] → [subplan](./phase-4-app-healthcheck.md)
- [ ] Phase 5: Board, Section & Widget System [fullstack] → [subplan](./phase-5-board-widgets.md)
- [ ] Phase 6: Admin Panel [fullstack] → [subplan](./phase-6-admin-panel.md)
@@ -42,7 +42,7 @@ Build a self-hosted web application launcher/dashboard for a TrueNAS server envi
|-------|--------|--------|--------|-------|-----------|
| Phase 1: Scaffolding | backend | ✅ Complete | ✅ | ⬜ | ⬜ |
| Phase 2: Database & Services | backend | ✅ Complete | ⬜ | ⬜ | ⬜ |
| Phase 3: Authentication | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
| Phase 3: Authentication | fullstack | ✅ Complete | ⬜ | ⬜ | ⬜ |
| Phase 4: App & Healthcheck | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
| Phase 5: Board & Widgets | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
| Phase 6: Admin Panel | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
@@ -1,6 +1,6 @@
# Phase 3: Authentication System
**Status:** ⬜ Not Started
**Status:** ✅ Complete
**Parent plan:** [PLAN.md](./PLAN.md)
**Domain:** fullstack
@@ -9,21 +9,21 @@ Implement the full local authentication flow: login, registration, session manag
## Tasks
- [ ] Task 1: Implement `src/lib/server/utils/jwt.ts`sign, verify, refresh token generation
- [ ] Task 2: Implement `src/lib/server/utils/password.ts`bcrypt hash/compare
- [ ] Task 3: Implement `src/hooks.server.ts` — auth middleware, session injection into `event.locals`
- [ ] Task 4: Create `src/routes/login/+page.server.ts` — login form action (Superforms + Zod)
- [ ] Task 5: Create `src/routes/login/+page.svelte` — login page UI
- [ ] Task 6: Create `src/routes/register/+page.server.ts` — registration form action (respects admin toggle)
- [ ] Task 7: Create `src/routes/register/+page.svelte` — registration page UI
- [ ] Task 8: Create `src/routes/auth/refresh/+server.ts` — token refresh endpoint
- [ ] Task 9: Create `src/routes/+layout.server.ts` — root layout load: inject user session
- [ ] Task 10: Create `src/routes/+layout.svelte` — root layout shell (minimal, polished in Phase 7)
- [ ] Task 11: Implement `src/lib/server/middleware/authenticate.ts` — reusable auth check helper
- [ ] Task 12: Implement `src/lib/server/middleware/authorize.ts` — role-based access check
- [ ] Task 13: Implement `src/lib/server/middleware/guestAccess.ts` — guest mode board visibility
- [ ] Task 14: Create `src/routes/+page.svelte` — root page (redirect to default board or login)
- [ ] Task 15: Create logout endpoint/action — invalidate refresh token, clear cookies
- [x] Task 1: Implement `src/lib/server/utils/jwt.ts`thin re-export from authService (already implemented in Phase 2)
- [x] Task 2: Implement `src/lib/server/utils/password.ts`thin re-export from authService (already implemented in Phase 2)
- [x] Task 3: Implement `src/hooks.server.ts` — auth middleware, session injection into `event.locals`
- [x] Task 4: Create `src/routes/login/+page.server.ts` — login form action (Superforms + Zod)
- [x] Task 5: Create `src/routes/login/+page.svelte` — login page UI
- [x] Task 6: Create `src/routes/register/+page.server.ts` — registration form action (respects admin toggle)
- [x] Task 7: Create `src/routes/register/+page.svelte` — registration page UI
- [x] Task 8: Create `src/routes/auth/refresh/+server.ts` — token refresh endpoint
- [x] Task 9: Create `src/routes/+layout.server.ts` — root layout load: inject user session
- [x] Task 10: Create `src/routes/+layout.svelte` — root layout shell (minimal, polished in Phase 7)
- [x] Task 11: Implement `src/lib/server/middleware/authenticate.ts` — reusable auth check helper
- [x] Task 12: Implement `src/lib/server/middleware/authorize.ts` — role-based access check
- [x] Task 13: Implement `src/lib/server/middleware/guestAccess.ts` — guest mode board visibility
- [x] Task 14: Create `src/routes/+page.svelte` — root page (redirect to default board or login)
- [x] Task 15: Create logout endpoint/action — invalidate refresh token, clear cookies
## Files to Modify/Create
- `src/hooks.server.ts` — auth middleware
@@ -40,7 +40,7 @@ Implement the full local authentication flow: login, registration, session manag
- `src/routes/+layout.server.ts`
- `src/routes/+layout.svelte`
- `src/routes/+page.svelte`
- `src/app.d.ts` — augment `Locals` with user session type
- `src/app.d.ts` — augment `Locals` with user session type (already done in Phase 2)
## Acceptance Criteria
- Users can register (when enabled) and log in with email/password
@@ -57,14 +57,27 @@ Implement the full local authentication flow: login, registration, session manag
- Store refresh tokens in DB (User model) for server-side invalidation
- OAuth is deferred to Phase 2 of the project (post-MVP)
- Registration toggle is read from SystemSettings
- ⚠️ Big Bang: login page will be functional but unstyled/minimal until Phase 7
- Big Bang: login page will be functional but unstyled/minimal until Phase 7
## Review Checklist
- [ ] All tasks completed
- [ ] Code follows project conventions
- [ ] No unintended side effects
- [x] All tasks completed
- [x] Code follows project conventions
- [x] No unintended side effects
- [ ] Build passes
- [ ] Tests pass (new + existing)
## Handoff to Next Phase
<!-- Filled in by the implementation agent after completing this phase. -->
**What's ready for Phase 4:**
- Full local auth flow is implemented: login, registration, logout, token refresh.
- `hooks.server.ts` validates JWT access tokens on every request and injects `event.locals.user` and `event.locals.session`. Expired access tokens are silently refreshed via refresh token rotation.
- Protected routes (anything except `/login`, `/register`, `/auth/*`, `/api/health`) redirect unauthenticated users to `/login`.
- Guest mode support: `guestAccess.ts` middleware checks `isGuestAccessible` on boards; hooks allow unauthenticated access to guest-accessible board routes.
- Reusable middleware helpers available: `requireAuth()`, `isAuthenticated()`, `requireRole()`, `requireAdmin()`.
- Login/register pages use Superforms + Zod with inline error display.
- Registration respects `SystemSettings.registrationEnabled` toggle.
- Root layout (`+layout.server.ts`) injects `user` into all page data.
- Root page (`+page.server.ts`) redirects to default board (authenticated) or guest board (unauthenticated) or `/login`.
- Logout endpoint at `POST /auth/logout` revokes refresh token and clears all auth cookies.
- `jwt.ts` and `password.ts` are thin re-exports from `authService` (no duplication).
- A `refresh_user_id` cookie is used alongside `refresh_token` to identify the user during token rotation (since refresh tokens are stored hashed per-user).