From 82ac5409099d05076c602faff2d47d09c3c0c2a8 Mon Sep 17 00:00:00 2001 From: Julien Calixte Date: Thu, 28 May 2026 01:09:48 +0200 Subject: [PATCH] feat(auth): Google OAuth, sealed session and default-deny gating (T9) Gate the app behind Google sign-in restricted to verified @theodo.com identities, and record the real reporter on filed defects (F9). - nuxt-auth-utils for sealed cookie sessions + the Google OAuth handler, mounted at /auth/google/callback to match the registered redirect URI. - isAllowedGoogleUser re-derives the domain from Google's verified email; the spoofable `hd` claim is deliberately ignored (DESIGN T9). - Default-deny: server middleware 401s unauthenticated /api calls (health and the session endpoint excepted); a global route middleware redirects unauthenticated page navigations to /login. - getReporter() now reads the session email instead of the dev stub. - Env contract moves to nuxt-auth-utils names (NUXT_SESSION_PASSWORD, NUXT_OAUTH_GOOGLE_*); .env.example, compose and README updated. Unit-tested: domain check (incl. hd-spoof + look-alike) and public-path matching. Live OAuth round-trip pending manual verification. --- .env.example | 15 ++- README.md | 6 +- app/layouts/default.vue | 12 ++ app/middleware/auth.global.ts | 13 ++ app/pages/login.vue | 32 +++++ docker-compose.yml | 8 +- nuxt.config.ts | 2 +- package.json | 1 + pnpm-lock.yaml | 142 ++++++++++++++++++++++ server/api/defects.post.ts | 2 +- server/middleware/auth.ts | 15 +++ server/routes/auth/google/callback.get.ts | 25 ++++ server/utils/allowedGoogleUser.ts | 21 ++++ server/utils/authPaths.ts | 12 ++ server/utils/getReporter.ts | 13 +- shared/auth.d.ts | 12 ++ tasks/todo.md | 6 +- tests/auth.spec.ts | 52 ++++++++ 18 files changed, 368 insertions(+), 21 deletions(-) create mode 100644 app/middleware/auth.global.ts create mode 100644 app/pages/login.vue create mode 100644 server/middleware/auth.ts create mode 100644 server/routes/auth/google/callback.get.ts create mode 100644 server/utils/allowedGoogleUser.ts create mode 100644 server/utils/authPaths.ts create mode 100644 shared/auth.d.ts create mode 100644 tests/auth.spec.ts diff --git a/.env.example b/.env.example index 1886d22..517ac38 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ -# App -NUXT_SESSION_SECRET=change-me +# App — session sealing key for nuxt-auth-utils (must be ≥32 chars) +NUXT_SESSION_PASSWORD=change-me-to-a-long-random-string-min-32-chars # Database (Postgres) — Coolify-managed in prod, docker-compose in dev DATABASE_URL=postgres://andon:andon@localhost:5432/andon @@ -9,10 +9,13 @@ POSTGRES_USER=andon POSTGRES_PASSWORD=andon POSTGRES_DB=andon -# Google OAuth (Task 9) — restricted to the theodo.com hosted domain -GOOGLE_CLIENT_ID= -GOOGLE_CLIENT_SECRET= -GOOGLE_REDIRECT_URI= +# Google OAuth (Task 9) — nuxt-auth-utils reads these exact names. Access is +# restricted server-side to verified @theodo.com emails (the `hd` claim is not +# trusted on its own). REDIRECT_URL must match an Authorized redirect URI in the +# Google Cloud console (defaults to /auth/google/callback if unset). +NUXT_OAUTH_GOOGLE_CLIENT_ID= +NUXT_OAUTH_GOOGLE_CLIENT_SECRET= +NUXT_OAUTH_GOOGLE_REDIRECT_URL= # Web Push / VAPID (Task 10) VAPID_PUBLIC_KEY= diff --git a/README.md b/README.md index 2b08d1a..88f8e7f 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,10 @@ migrate step is needed. 1. Point Coolify at this repo; it builds the production `Dockerfile`. 2. Create a **managed Postgres** in Coolify (automatic backups — [ADR 0003](./docs/adr/0003-use-coolify-managed-postgres-over-sqlite.md)) and set `DATABASE_URL` to it. _(Alternatively deploy `docker-compose.yml`, which bundles a Postgres service.)_ -3. Set the env vars from [`.env.example`](./.env.example) (`NUXT_SESSION_SECRET`, - Google OAuth, VAPID) and route `andon.apoena.dev` to the service. +3. Set the env vars from [`.env.example`](./.env.example) (`NUXT_SESSION_PASSWORD`, + `NUXT_OAUTH_GOOGLE_*`, VAPID) and route `andon.apoena.dev` to the service. Add + `https://andon.apoena.dev/auth/google/callback` as an Authorized redirect URI + in the Google Cloud OAuth client. 4. **Enable Coolify's autodeploy** so it builds and deploys on every push to `main`. Protect `main` with required PR review + CI so only vetted commits reach production. diff --git a/app/layouts/default.vue b/app/layouts/default.vue index 334d9db..d6e8677 100644 --- a/app/layouts/default.vue +++ b/app/layouts/default.vue @@ -1,6 +1,12 @@