← Cycles
Market Analyst · c3

oauth

parkedparked — see PICKUP.mdcreated 2026-02-20· last activity 2026-08-20

Add Google OAuth to restrict dashboard access to @qpoint.io team members.

Why

The market analysis dashboard is currently open to anyone with the URL. As the data grows and the dashboard gets shared more broadly, we need to restrict access to the Qpoint team. Google OAuth is the natural fit since the team already uses Google Workspace.

Objective

Add Google OAuth login using nuxt-auth-utils. "Done" means: only users with @qpoint.io Google accounts can access the dashboard, sessions persist via encrypted cookies, and the nav shows the logged-in user with a sign-out option.

Scope

  • site/ — Nuxt 3 dashboard (auth module, server routes, middleware, login page, layout)
  • .env — New OAuth credentials
  • package.json (root) — Update dev/build scripts for .env loading

Prerequisites (manual)

  1. In Google Cloud Console, go to APIs & Services > Credentials
  2. Create an OAuth 2.0 Client ID (Web application)
  3. Authorized redirect URIs:
    • http://localhost:3000/auth/google (dev)
    • https://<production-domain>/auth/google (prod)
  4. Set OAuth consent screen to Internal (restricts to Qpoint Workspace org)
  5. Note the Client ID and Client Secret

Implementation Plan

1. Install nuxt-auth-utils

Run npx nuxi@latest module add auth-utils from site/.

2. Add env vars to .env

NUXT_SESSION_PASSWORD=<random-32+-char-string>
NUXT_OAUTH_GOOGLE_CLIENT_ID=<from-google-cloud>
NUXT_OAUTH_GOOGLE_CLIENT_SECRET=<from-google-cloud>

3. Update dev/build scripts

Root package.json — add --dotenv ../.env to nuxt commands so they find the root .env.

4. Update nuxt.config.ts

Add nuxt-auth-utils to modules, add runtimeConfig block for session/oauth defaults.

5. Create Google OAuth server route

New: site/server/routes/auth/google.get.ts

  • defineOAuthGoogleEventHandler with email+profile scopes
  • Check email ends with @qpoint.io, reject others → /login?error=unauthorized
  • Store { email, name, avatar } in encrypted cookie session

6. Create global auth middleware

New: site/middleware/auth.global.ts

  • Check useUserSession().loggedIn on every route
  • Redirect to /login if not authenticated (skip /login itself)

7. Create login page

New: site/pages/login.vue

  • Full-screen dark layout (no nav bar)
  • Qpoint logo + "Sign in with Google" button → /auth/google
  • Error messages for unauthorized/oauth-failure query params

8. Add user info + logout to nav

Modify: site/layouts/default.vue

  • Show user avatar, name, and "Sign out" button after nav links
  • Sign out clears session and redirects to /login

9. Add session type definition

New: site/auth.d.ts — type the User shape for autocomplete

Files

ActionFile
Modifypackage.json (root) — --dotenv ../.env in site scripts
Modifysite/nuxt.config.ts — module + runtimeConfig
Modify.env — 3 new OAuth env vars
Modifysite/layouts/default.vue — user info + logout
Createsite/server/routes/auth/google.get.ts — OAuth handler
Createsite/middleware/auth.global.ts — route protection
Createsite/pages/login.vue — login page
Createsite/auth.d.ts — TypeScript types

Notes

  • /data/*.json is served as Nitro public assets (bypasses auth). Fine for now — auth protects the UI. Can move to authenticated API routes later if needed.
  • Setting the Google consent screen to "Internal" adds a second layer of domain restriction at Google's level.

Verification

  1. npm run dev → redirects to /login
  2. "Sign in with Google" → Google consent screen
  3. @qpoint.io account → dashboard with name/avatar in nav
  4. Non-@qpoint.io account → "Access denied" on login page
  5. "Sign out" → clears session, back to login
  6. Direct URL while logged out → redirects to /login

Artifacts

Qpoint Brand Style Guide