- 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>
6.0 KiB
Implementation Plan: Google OAuth Authentication Screen
Branch: 001-google-oauth-auth | Date: 2026-01-29 | Spec: spec.md
Input: Feature specification from /specs/001-google-oauth-auth/spec.md
Summary
Implement a Google OAuth 2.0 authentication screen that gates access to the ThumbPreview tool. Users must authenticate via Google before accessing protected routes (/tool). The implementation uses redirect-based OAuth flow with session persistence (7-day validity), preserving the user's originally requested destination after login. Backend handles OAuth callback and session management; frontend provides auth UI and route protection.
Technical Context
Language/Version: TypeScript 5.x (frontend + backend) Primary Dependencies:
- Frontend: React 19.x, React Router 7.x, Zustand 5.x, @tanstack/react-query 5.x, shadcn/ui
- Backend: NestJS 11.x, TypeORM 0.3.x, @nestjs/passport, passport-google-oauth20 Storage: PostgreSQL (users, sessions via TypeORM) Testing: Jest (backend), manual testing (frontend) Target Platform: Web (desktop + mobile browsers) Project Type: Web application (frontend + backend monorepo) Performance Goals: OAuth flow completion < 30 seconds, session validation < 100ms Constraints: Must work with existing Vite proxy setup, no .env in frontend Scale/Scope: Single user role, 7-day session validity with refresh
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
| Principle | Status | Notes |
|---|---|---|
| I. Tech Stack | ✅ PASS | Using React 19, NestJS 11, TypeORM, PostgreSQL per constitution |
| II. Architecture | ✅ PASS | Following monorepo structure: frontend/src/, backend/src/modules/ |
| III. Styling & UI | ✅ PASS | Will use shadcn/ui Button, Card components with Tailwind |
| IV. Data Management | ✅ PASS | Zustand for auth state, React Query for user data, TypeORM for persistence |
| V. Development Practices | ✅ PASS | TypeScript strict mode, class-validator DTOs, ESLint |
New Dependencies Required:
@nestjs/passport+passport+passport-google-oauth20- OAuth authentication (NestJS official, MIT license)@types/passport-google-oauth20- TypeScript types
Justification: Passport.js is the de facto standard for Node.js authentication. @nestjs/passport provides official NestJS integration. These are well-maintained, MIT-licensed, and have minimal bundle impact (backend only).
Project Structure
Documentation (this feature)
specs/001-google-oauth-auth/
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── quickstart.md # Phase 1 output
├── contracts/ # Phase 1 output
│ └── auth-api.yaml # OpenAPI spec for auth endpoints
└── tasks.md # Phase 2 output (/speckit.tasks command)
Source Code (repository root)
backend/
├── src/
│ ├── modules/
│ │ ├── auth/ # NEW: Authentication module
│ │ │ ├── auth.module.ts
│ │ │ ├── auth.controller.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── google.strategy.ts
│ │ │ ├── jwt.strategy.ts
│ │ │ ├── guards/
│ │ │ │ ├── jwt-auth.guard.ts
│ │ │ │ └── google-auth.guard.ts
│ │ │ └── dto/
│ │ │ └── auth-response.dto.ts
│ │ ├── thumbnails/ # Existing
│ │ └── youtube/ # Existing
│ └── entities/
│ ├── user.entity.ts # NEW
│ ├── thumbnail.entity.ts # Existing
│ └── youtube-cache.entity.ts # Existing
└── tests/
frontend/
├── src/
│ ├── components/
│ │ ├── AuthGuard.tsx # NEW: Route protection wrapper
│ │ └── UserMenu.tsx # NEW: User avatar + sign out
│ ├── pages/
│ │ ├── LoginPage.tsx # NEW: Auth screen
│ │ ├── AuthCallbackPage.tsx # NEW: OAuth callback handler
│ │ ├── LandingPage.tsx # Existing (public)
│ │ └── ToolPage.tsx # Existing (protected)
│ ├── store/
│ │ └── authStore.ts # NEW: Auth state (Zustand)
│ ├── api/
│ │ └── auth.ts # NEW: Auth API client
│ └── hooks/
│ └── useAuth.ts # NEW: Auth hook
└── tests/
Structure Decision: Web application structure with frontend/backend separation per constitution. Auth module added to backend following NestJS module pattern. Frontend gets new pages for login flow and components for route protection.
Complexity Tracking
No constitution violations. All implementation follows established patterns.
Post-Design Constitution Re-Check
Re-validated after Phase 1 design completion.
| Principle | Status | Validation |
|---|---|---|
| I. Tech Stack | ✅ PASS | Dependencies align: @nestjs/passport, passport-google-oauth20 (MIT, maintained) |
| II. Architecture | ✅ PASS | Auth module follows NestJS pattern, frontend follows components/pages/store structure |
| III. Styling & UI | ✅ PASS | LoginPage will use shadcn/ui Button, Card; Tailwind for layout |
| IV. Data Management | ✅ PASS | User entity uses UUID PK, Zustand for auth state, TypeORM for persistence |
| V. Development Practices | ✅ PASS | DTOs with class-validator, explicit TypeScript types, ESLint compliance |
Phase 1 Artifacts Generated:
- ✅
research.md- OAuth implementation patterns documented - ✅
data-model.md- User and RefreshToken entities defined - ✅
contracts/auth-api.yaml- OpenAPI spec for 5 auth endpoints - ✅
quickstart.md- Setup and testing guide - ✅
CLAUDE.md- Agent context updated with new technologies