From cbe638b1af72963830dc53ea085d22c00029a95e Mon Sep 17 00:00:00 2001 From: lila Date: Sun, 12 Apr 2026 10:18:16 +0200 Subject: [PATCH] docs: update auth references from OpenAuth to Better Auth --- documentation/decisions.md | 8 ++++---- documentation/roadmap.md | 21 ++++++++++----------- documentation/spec.md | 11 +++++------ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/documentation/decisions.md b/documentation/decisions.md index 11ab391..71dc921 100644 --- a/documentation/decisions.md +++ b/documentation/decisions.md @@ -22,9 +22,9 @@ Drizzle is lighter — no binary, no engine. Queries map closely to SQL. Migrati For rooms of 2–4 players, Socket.io's room management, transport fallbacks, and reconnection abstractions are unnecessary overhead. The WS protocol is defined explicitly as a Zod discriminated union in `packages/shared`, giving the same type safety guarantees. Reconnection logic is deferred to Phase 7. -### Auth: OpenAuth (not rolling own JWT) +### Auth: Better Auth (not OpenAuth or Keycloak) -All auth delegated to OpenAuth service at `auth.yourdomain.com`. Providers: Google, GitHub. The API validates the JWT on every protected request. User rows are created or updated on first login via the `sub` claim as the primary key. +Better Auth embeds as middleware in the Express API — no separate auth service or Docker container. It connects to the existing PostgreSQL via the Drizzle adapter and manages its own tables (user, session, account, verification). Social providers (Google, GitHub) are configured in a single config object. Session validation is a function call within the same process, not a network request. OpenAuth was considered but requires a standalone service and leaves user management to you. Keycloak is too heavy for a single-app project. --- @@ -198,9 +198,9 @@ Vitest coverage configuration lives in the root `vitest.config.ts` only. Produce ## Data Model -### Users: internal UUID + openauth_sub (not sub as PK) +### Users: Better Auth manages the user table -Embeds auth provider in the primary key would cascade through all FKs if OpenAuth changes format. `users.id` = internal UUID (stable FK target). `users.openauth_sub` = text UNIQUE (auth provider claim). +Better Auth creates and owns the user table (plus session, account, verification). The account table links social provider identities to users — one user can have both Google and GitHub linked. Other tables (rooms, stats) reference user.id via FK. No need to design a custom user schema or handle provider-specific claims manually. ### Rooms: `updated_at` for stale recovery only diff --git a/documentation/roadmap.md b/documentation/roadmap.md index 7739770..7599704 100644 --- a/documentation/roadmap.md +++ b/documentation/roadmap.md @@ -87,19 +87,18 @@ Each phase produces a working increment. Nothing is built speculatively. ## Phase 3 — Auth **Goal:** Users can log in via Google or GitHub and stay logged in. -**Done when:** JWT from OpenAuth is validated by the API; protected routes redirect unauthenticated users; user row is created on first login. +**Done when:** Better Auth session is validated on protected routes; unauthenticated users are redirected to login; user row is created on first social login. -- [ ] Add OpenAuth service to `docker-compose.yml` -- [ ] Write Drizzle schema: `users` (uuid `id`, text `openauth_sub`) -- [ ] Write and run migration -- [ ] Implement JWT validation middleware in `apps/api` -- [ ] Implement `GET /api/auth/me` (validate token, upsert user row, return user) -- [ ] Define auth Zod schemas in `packages/shared` +- [ ] Install `better-auth` and configure with Drizzle adapter + PostgreSQL +- [ ] Mount Better Auth handler on `/api/auth/*` in `app.ts` +- [ ] Configure Google and GitHub social providers +- [ ] Run Better Auth CLI to generate and migrate auth tables (user, session, account, verification) +- [ ] Add session validation middleware for protected API routes +- [ ] Frontend: install `better-auth/react` client - [ ] Frontend: login page with Google + GitHub buttons -- [ ] Frontend: redirect to auth service → receive JWT → store in memory + HttpOnly cookie -- [ ] Frontend: TanStack Router auth guard -- [ ] Frontend: TanStack Query `api.ts` attaches token to every request -- [ ] Unit tests for JWT middleware +- [ ] Frontend: TanStack Router auth guard using `useSession` +- [ ] Frontend: TanStack Query `api.ts` sends credentials with every request +- [ ] Unit tests for session middleware --- diff --git a/documentation/spec.md b/documentation/spec.md index 0236c01..5c297a8 100644 --- a/documentation/spec.md +++ b/documentation/spec.md @@ -24,7 +24,7 @@ The vocabulary data comes from WordNet + the Open Multilingual Wordnet (OMW). A ## 2. Full Product Vision (Long-Term) -- Users log in via Google or GitHub (OpenAuth) +- Users log in via Google or GitHub (Better Auth) - Singleplayer mode: 10-round quiz, score screen - Multiplayer mode: create a room, share a code, 2–4 players answer simultaneously in real time, live scores, winner screen - 1000+ English–Italian nouns seeded from WordNet @@ -51,7 +51,7 @@ This is the full vision. The MVP deliberately ignores most of it. | Feature | Why cut | | ------------------------------- | -------------------------------------- | -| Authentication (OpenAuth) | No user accounts needed for a demo | +| Authentication (Better Auth) | No user accounts needed for a demo | | Multiplayer (WebSockets, rooms) | Core quiz works without it | | Valkey / Redis cache | Only needed for multiplayer room state | | Deployment to Hetzner | Ship to people locally first | @@ -77,7 +77,7 @@ The monorepo structure and tooling are already set up. This is the full stack | Database | PostgreSQL + Drizzle ORM | ✅ | | Validation | Zod (shared schemas) | ✅ | | Testing | Vitest, supertest | ✅ | -| Auth | OpenAuth (Google + GitHub) | ❌ post-MVP | +| Auth | Better Auth (Google + GitHub) | ❌ post-MVP | | Realtime | WebSockets (`ws` library) | ❌ post-MVP | | Cache | Valkey | ❌ post-MVP | | Deployment | Docker Compose, Hetzner, Nginx | ❌ post-MVP | @@ -260,7 +260,7 @@ After completing a task: share the code, ask what to refactor and why. The LLM s | Phase | What it adds | | ----------------- | -------------------------------------------------------------- | -| Auth | OpenAuth (Google + GitHub), JWT middleware, user rows in DB | +| Auth | Auth | Better Auth (Google + GitHub), embedded in Express API, user rows in DB | | User Stats | Games played, score history, profile page | | Multiplayer Lobby | Room creation, join by code, WebSocket connection | | Multiplayer Game | Simultaneous answers, server timer, live scores, winner screen | @@ -288,8 +288,7 @@ All are new tables referencing existing `terms` rows via FK. No existing schema ### Infrastructure (deferred) - `app.yourdomain.com` → React frontend -- `api.yourdomain.com` → Express API + WebSocket -- `auth.yourdomain.com` → OpenAuth service +- `api.yourdomain.com` → Express API + WebSocket + Better Auth - Docker Compose with `nginx-proxy` + `acme-companion` for automatic SSL ---