# Tasks: Google OAuth Authentication Screen **Input**: Design documents from `/specs/001-google-oauth-auth/` **Prerequisites**: plan.md ✅, spec.md ✅, research.md ✅, data-model.md ✅, contracts/ ✅ **Tests**: Not explicitly requested - manual testing via quickstart.md **Organization**: Tasks grouped by user story to enable independent implementation and testing. ## Format: `[ID] [P?] [Story] Description` - **[P]**: Can run in parallel (different files, no dependencies) - **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3) - Include exact file paths in descriptions ## Path Conventions - **Web app**: `backend/src/`, `frontend/src/` --- ## Phase 1: Setup (Shared Infrastructure) **Purpose**: Install dependencies and configure project for OAuth authentication - [x] T001 Install backend auth dependencies: `cd backend && npm install @nestjs/passport @nestjs/jwt passport passport-google-oauth20 bcrypt` - [x] T002 Install backend auth type definitions: `cd backend && npm install -D @types/passport-google-oauth20 @types/bcrypt` - [x] T003 [P] Add OAuth environment variables template to backend/.env.example (GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_CALLBACK_URL, JWT_SECRET, JWT_ACCESS_EXPIRATION, JWT_REFRESH_EXPIRATION, FRONTEND_URL) - [x] T004 [P] Update backend/src/app.module.ts to import ConfigModule with .env support - [x] T005 Configure CORS in backend/src/main.ts with credentials: true and FRONTEND_URL origin --- ## Phase 2: Foundational (Blocking Prerequisites) **Purpose**: Core entities, auth module structure, and database schema that ALL user stories depend on **⚠️ CRITICAL**: No user story work can begin until this phase is complete - [x] T006 Create User entity in backend/src/entities/user.entity.ts with fields: id (UUID), googleId, email, displayName, avatarUrl, createdAt, lastLoginAt - [x] T007 [P] Create RefreshToken entity in backend/src/entities/refresh-token.entity.ts with fields: id (UUID), userId (FK), token, expiresAt, createdAt, revokedAt - [x] T008 Register User and RefreshToken entities in backend/src/app.module.ts TypeORM configuration - [x] T009 Create auth module scaffold in backend/src/modules/auth/ with auth.module.ts, auth.controller.ts, auth.service.ts - [x] T010 [P] Create DTOs in backend/src/modules/auth/dto/: auth-response.dto.ts, user-response.dto.ts - [x] T011 [P] Create auth types in frontend/src/types/auth.ts: User interface, AuthState interface - [x] T012 Create auth store in frontend/src/store/authStore.ts using Zustand with: user, accessToken, isLoading, setAuth, clearAuth, setLoading - [x] T013 [P] Create auth API client in frontend/src/api/auth.ts with axios instance and methods: refreshToken, getMe, logout **Checkpoint**: Foundation ready - user story implementation can now begin --- ## Phase 3: User Story 1 - First-Time User Sign In (Priority: P1) 🎯 MVP **Goal**: New user can authenticate via Google OAuth and access the tool page **Independent Test**: Visit /tool as logged-out user → redirected to login → click "Sign in with Google" → complete Google OAuth → redirected to /tool with active session ### Backend Implementation for User Story 1 - [x] T014 [US1] Implement GoogleStrategy in backend/src/modules/auth/google.strategy.ts using passport-google-oauth20 - [x] T015 [US1] Implement JwtStrategy in backend/src/modules/auth/jwt.strategy.ts for access token validation - [x] T016 [P] [US1] Create GoogleAuthGuard in backend/src/modules/auth/guards/google-auth.guard.ts - [x] T017 [P] [US1] Create JwtAuthGuard in backend/src/modules/auth/guards/jwt-auth.guard.ts - [x] T018 [US1] Implement AuthService.validateOAuthUser() in backend/src/modules/auth/auth.service.ts - creates/updates user, issues tokens - [x] T019 [US1] Implement AuthService.generateTokens() for JWT access token and refresh token generation with bcrypt hashing - [x] T020 [US1] Add GET /auth/google route in backend/src/modules/auth/auth.controller.ts with GoogleAuthGuard - [x] T021 [US1] Add GET /auth/google/callback route in backend/src/modules/auth/auth.controller.ts - handle OAuth callback, set HttpOnly cookie, redirect to frontend - [x] T022 [US1] Add GET /auth/me route in backend/src/modules/auth/auth.controller.ts with JwtAuthGuard - [x] T023 [US1] Register AuthModule in backend/src/app.module.ts imports ### Frontend Implementation for User Story 1 - [x] T024 [P] [US1] Create LoginPage component in frontend/src/pages/LoginPage.tsx with "Sign in with Google" button using shadcn/ui Button and Card - [x] T025 [P] [US1] Create AuthCallbackPage component in frontend/src/pages/AuthCallbackPage.tsx to handle OAuth callback token from URL - [x] T026 [US1] Implement useAuth hook in frontend/src/hooks/useAuth.ts with checkAuth, login redirect, and loading state - [x] T027 [US1] Create AuthGuard component in frontend/src/components/AuthGuard.tsx - redirects to /login if not authenticated, preserves intended destination in location.state - [x] T028 [US1] Update frontend/src/App.tsx - add /login route, /auth/callback route, wrap /tool with AuthGuard - [x] T029 [US1] Handle OAuth errors in LoginPage - display error message from URL params if authentication failed **Checkpoint**: User Story 1 complete - new users can sign in via Google and access protected routes --- ## Phase 4: User Story 2 - Returning User Session (Priority: P2) **Goal**: Returning user with valid session bypasses login; expired session redirects to login **Independent Test**: Sign in → close browser → return within 7 days → automatically access /tool without login prompt ### Backend Implementation for User Story 2 - [x] T030 [US2] Add POST /auth/refresh route in backend/src/modules/auth/auth.controller.ts - validate HttpOnly refresh cookie, rotate token, return new access token - [x] T031 [US2] Implement AuthService.refreshTokens() in backend/src/modules/auth/auth.service.ts - validate stored token, check expiry, issue new pair - [x] T032 [US2] Implement AuthService.revokeRefreshToken() for token rotation (mark old token as revoked) ### Frontend Implementation for User Story 2 - [x] T033 [US2] Add silent token refresh on app mount in frontend/src/hooks/useAuth.ts - call /auth/refresh on startup - [x] T034 [US2] Add Axios response interceptor in frontend/src/api/auth.ts - on 401, attempt refresh, retry original request - [x] T035 [US2] Update AuthGuard in frontend/src/components/AuthGuard.tsx - show loading state during session check, then redirect or render **Checkpoint**: User Story 2 complete - returning users have seamless session persistence --- ## Phase 5: User Story 3 - User Sign Out (Priority: P3) **Goal**: Authenticated user can sign out, which clears session and returns to login **Independent Test**: Sign in → click sign out in user menu → redirected to login → cannot access /tool ### Backend Implementation for User Story 3 - [x] T036 [US3] Add POST /auth/logout route in backend/src/modules/auth/auth.controller.ts with JwtAuthGuard - revoke refresh token, clear cookie ### Frontend Implementation for User Story 3 - [x] T037 [P] [US3] Create UserMenu component in frontend/src/components/UserMenu.tsx - display user avatar, name, sign out button using shadcn/ui - [x] T038 [US3] Implement logout function in frontend/src/store/authStore.ts - call /auth/logout, clear local state - [x] T039 [US3] Add UserMenu to ToolPage header in frontend/src/pages/ToolPage.tsx **Checkpoint**: User Story 3 complete - users can sign out securely --- ## Phase 6: Polish & Cross-Cutting Concerns **Purpose**: Error handling, edge cases, and final validation - [x] T040 [P] Add error handling for OAuth failures in backend/src/modules/auth/auth.controller.ts - redirect to frontend with error param - [x] T041 [P] Add error display component for auth errors in frontend/src/pages/LoginPage.tsx - show user-friendly messages - [x] T042 Update Vite proxy configuration in frontend/vite.config.ts if needed for /api/auth routes - [x] T043 Validate implementation against quickstart.md test scenarios - [x] T044 Run ESLint and fix any linting errors in new files --- ## Dependencies & Execution Order ### Phase Dependencies - **Setup (Phase 1)**: No dependencies - can start immediately - **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS all user stories - **User Stories (Phase 3-5)**: All depend on Foundational phase completion - **Polish (Phase 6)**: Depends on all user stories being complete ### User Story Dependencies - **User Story 1 (P1)**: Can start after Foundational (Phase 2) - Core sign-in flow - **User Story 2 (P2)**: Can start after Foundational (Phase 2) - Extends US1 with token refresh, but independently testable - **User Story 3 (P3)**: Can start after Foundational (Phase 2) - Adds logout to US1, independently testable ### Within Each User Story - Backend before frontend (API must exist before UI calls it) - Entity/strategy before service - Service before controller - Controller before frontend integration ### Parallel Opportunities **Phase 1 (Setup)**: ``` T003 [P] + T004 [P] can run in parallel ``` **Phase 2 (Foundational)**: ``` T006 + T007 [P] can run in parallel (different entity files) T010 [P] + T011 [P] + T013 [P] can run in parallel (DTOs, types, API client) ``` **Phase 3 (User Story 1)**: ``` T016 [P] + T017 [P] can run in parallel (different guard files) T024 [P] + T025 [P] can run in parallel (different page files) ``` --- ## Implementation Strategy ### MVP First (User Story 1 Only) 1. Complete Phase 1: Setup (T001-T005) 2. Complete Phase 2: Foundational (T006-T013) 3. Complete Phase 3: User Story 1 (T014-T029) 4. **STOP and VALIDATE**: Test sign-in flow per quickstart.md 5. Deploy/demo if ready - users can now sign in! ### Incremental Delivery 1. Complete Setup + Foundational → Foundation ready 2. Add User Story 1 → Test independently → Deploy (MVP with sign-in) 3. Add User Story 2 → Test independently → Deploy (session persistence) 4. Add User Story 3 → Test independently → Deploy (full auth with logout) 5. Complete Polish → Final validation → Production ready ### Task Count by Story | Phase | Task Count | |-------|------------| | Setup | 5 | | Foundational | 8 | | User Story 1 | 16 | | User Story 2 | 6 | | User Story 3 | 4 | | Polish | 5 | | **Total** | **44** | --- ## Notes - [P] tasks = different files, no dependencies - [Story] label maps task to specific user story for traceability - Each user story is independently completable and testable - Backend entities use UUID primary keys per constitution - Frontend uses shadcn/ui components per constitution - HttpOnly cookies for refresh tokens per research.md security recommendations