- Add Google OAuth 2.0 login flow with passport-google-oauth20 - Create User and RefreshToken entities for session management - Implement JWT access tokens (15min) + HttpOnly refresh cookies (7 days) - Add auth endpoints: /google, /google/callback, /refresh, /me, /logout - Create LoginPage with Google sign-in button (shadcn/ui) - Add AuthGuard for protected routes with redirect preservation - Implement silent token refresh on app mount - Add UserMenu component with avatar and sign-out Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
222 lines
10 KiB
Markdown
222 lines
10 KiB
Markdown
# 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
|