# Story 3.1: User Authentication System ## Status ✅ Complete ## Story **As a** user **I want** to create an account and login **So that** I can access my summary history across devices and have a personalized experience ## Acceptance Criteria 1. Email/password registration with verification email 2. Secure password requirements enforced (minimum 8 characters, complexity rules) 3. JWT-based authentication with refresh tokens 4. Password reset functionality via email 5. Optional OAuth integration with Google for single sign-on 6. Session management with automatic logout after inactivity ## Tasks / Subtasks - [x] **Task 1: Database Schema and Models** (AC: 1, 2, 3, 6) ✅ - [x] Install authentication dependencies (python-jose, passlib, email-validator) - [x] Create User model with email, password_hash, is_verified fields - [x] Create RefreshToken model for JWT refresh token storage - [x] Create APIKey model for future API access - [x] Initialize Alembic and create initial migration - [x] **Task 2: JWT Authentication Service** (AC: 3, 6) ✅ - [x] Implement JWT token generation (access + refresh tokens) - [x] Create token verification and decoding functions - [x] Implement refresh token rotation mechanism - [x] Add session timeout configuration (default 30 minutes) - [x] Create authentication dependency for protected routes - [x] **Task 3: User Registration System** (AC: 1, 2) ✅ - [x] Create POST /api/auth/register endpoint - [x] Implement password validation (min 8 chars, 1 upper, 1 lower, 1 number) - [x] Hash passwords using bcrypt with salt - [x] Generate email verification token - [x] Send verification email on registration - [x] **Task 4: Email Service** (AC: 1, 4) ✅ - [x] Configure SMTP settings (use MailHog for development) - [x] Create email templates for verification and password reset - [x] Implement async email sending with aiosmtplib - [x] Add email queue for retry on failure - [x] Create email verification endpoint - [x] **Task 5: Login and Session Management** (AC: 3, 6) ✅ - [x] Create POST /api/auth/login endpoint - [x] Validate credentials and return JWT tokens - [x] Implement refresh token endpoint - [x] Create logout endpoint with token revocation - [x] Add session activity tracking for auto-logout - [x] **Task 6: Password Reset Flow** (AC: 4) ✅ - [x] Create password reset request endpoint - [x] Generate secure reset token with expiration - [x] Send password reset email - [x] Create password reset confirmation endpoint - [x] Invalidate reset token after use - [x] **Task 7: Frontend Authentication Context** (AC: 3, 6) ✅ - [x] Create AuthContext with JWT token management - [x] Implement useAuth hook for auth state - [x] Add automatic token refresh on 401 responses - [x] Create protected route wrapper component - [x] Handle session timeout in UI - [x] **Task 8: Frontend Authentication Components** (AC: 1, 2, 4) ✅ - [x] Build LoginForm component with validation - [x] Create RegisterForm with password strength indicator - [x] Implement ForgotPasswordForm component - [x] Add EmailVerification handler component - [x] Create UserMenu dropdown for authenticated users - [x] **Task 9: Authentication Pages** (AC: 1, 4, 5) ✅ - [x] Create login page with form and OAuth option placeholder - [x] Build registration page with terms acceptance - [x] Implement forgot password page - [x] Create email verification landing page - [x] Add password reset confirmation page - [ ] **Task 10: OAuth Google Integration** (AC: 5) - Future Enhancement - [ ] Configure Google OAuth2 credentials - [ ] Implement OAuth flow endpoints - [ ] Add Google login button to UI - [ ] Handle OAuth callback and user creation - [ ] Link OAuth accounts to existing users - [x] **Task 11: Security and Testing** (AC: 2, 3, 6) ✅ - [x] Add rate limiting for auth endpoints (5 attempts per minute) - via middleware - [x] Implement CSRF protection for state-changing operations - via JWT - [x] Write unit tests for auth service (>80% coverage) - [x] Create integration tests for all auth endpoints - [ ] Add E2E tests for complete auth flows - Future when frontend ready ## Dev Notes ### Architecture Context This story introduces user authentication to transform the YouTube Summarizer from an anonymous tool to a personalized platform. The authentication system follows JWT best practices with short-lived access tokens (15 minutes) and longer refresh tokens (7 days) stored securely. ### Database Schema [Source: Epic 3 - User Model] ```python # backend/models/user.py from sqlalchemy import Column, String, Boolean, DateTime, ForeignKey from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship import uuid from datetime import datetime class User(Base): __tablename__ = "users" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) email = Column(String(255), unique=True, nullable=False, index=True) password_hash = Column(String(255), nullable=False) is_verified = Column(Boolean, default=False) is_active = Column(Boolean, default=True) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) last_login = Column(DateTime) # Relationships refresh_tokens = relationship("RefreshToken", back_populates="user", cascade="all, delete-orphan") summaries = relationship("Summary", back_populates="user") api_keys = relationship("APIKey", back_populates="user") class RefreshToken(Base): __tablename__ = "refresh_tokens" id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=False) token_hash = Column(String(255), unique=True, nullable=False, index=True) expires_at = Column(DateTime, nullable=False) revoked = Column(Boolean, default=False) created_at = Column(DateTime, default=datetime.utcnow) user = relationship("User", back_populates="refresh_tokens") ``` ### JWT Configuration [Source: docs/architecture.md#security] ```python # backend/core/config.py additions class AuthSettings(BaseSettings): JWT_SECRET_KEY: str = Field(..., env="JWT_SECRET_KEY") # Generate with: openssl rand -hex 32 JWT_ALGORITHM: str = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: int = 15 REFRESH_TOKEN_EXPIRE_DAYS: int = 7 EMAIL_VERIFICATION_EXPIRE_HOURS: int = 24 PASSWORD_RESET_EXPIRE_MINUTES: int = 30 # Email settings SMTP_HOST: str = Field("localhost", env="SMTP_HOST") SMTP_PORT: int = Field(1025, env="SMTP_PORT") # MailHog default SMTP_USER: Optional[str] = Field(None, env="SMTP_USER") SMTP_PASSWORD: Optional[str] = Field(None, env="SMTP_PASSWORD") SMTP_FROM_EMAIL: str = Field("noreply@youtube-summarizer.local", env="SMTP_FROM_EMAIL") ``` ### API Endpoint Structure All authentication endpoints follow RESTful conventions under `/api/auth/`: ``` POST /api/auth/register - Create new user account POST /api/auth/login - Authenticate and receive tokens POST /api/auth/refresh - Refresh access token POST /api/auth/logout - Revoke refresh token POST /api/auth/verify-email - Verify email with token POST /api/auth/resend-verification - Resend verification email POST /api/auth/reset-password - Request password reset POST /api/auth/reset-password/confirm - Confirm password reset GET /api/auth/me - Get current user profile (protected) ``` ### Frontend Authentication Flow The frontend uses React Context API for auth state management with automatic token refresh: ```typescript // frontend/src/contexts/AuthContext.tsx interface AuthContextType { user: User | null; isAuthenticated: boolean; isLoading: boolean; login: (email: string, password: string) => Promise; register: (email: string, password: string) => Promise; logout: () => void; refreshToken: () => Promise; } ``` ### Security Considerations - Passwords hashed with bcrypt (cost factor 12) - JWT tokens signed with HS256 algorithm - Refresh tokens hashed before database storage - Rate limiting: 5 login attempts per IP per minute - CORS configured for frontend origin only - HttpOnly cookies for refresh token storage (production) - CSRF tokens for state-changing operations ### Testing Standards [Source: docs/architecture.md#testing] - **Unit Tests**: `backend/tests/unit/test_auth_service.py` - Test JWT generation and validation - Test password hashing and verification - Test email token generation - Mock external dependencies (database, email) - **Integration Tests**: `backend/tests/integration/test_auth_api.py` - Test complete registration flow - Test login with valid/invalid credentials - Test token refresh mechanism - Test password reset flow - Use test database with rollback - **Frontend Tests**: `frontend/src/components/auth/__tests__/` - Test form validation - Test error handling - Test auth context behavior - Mock API responses ## Change Log | Date | Version | Description | Author | |------|---------|-------------|--------| | 2025-08-26 | 1.0 | Initial story creation | Claude (Scrum Master) | ## Dev Agent Record ### Agent Model Used _To be populated during implementation_ ### Debug Log References _To be populated during implementation_ ### Completion Notes List _To be populated during implementation_ ### File List **Backend Files Created/Modified:** - `backend/models/user.py` - User, RefreshToken, APIKey, EmailVerificationToken, PasswordResetToken models - `backend/models/api_models.py` - BaseResponse, ErrorResponse, SuccessResponse classes - `backend/services/auth_service.py` - Authentication logic, JWT handling, password management - `backend/services/email_service.py` - Email sending, templates, verification - `backend/services/ai_service.py` - Added ModelUsage dataclass - `backend/api/auth.py` - Authentication endpoints - `backend/core/config.py` - AuthSettings configuration - `backend/core/security.py` - Password hashing, JWT utilities - `backend/core/dependencies.py` - get_current_user, require_user dependencies - `backend/core/exceptions.py` - Authentication exceptions, YouTubeError - `backend/models/video.py` - Added VideoSummary model - `backend/main.py` - Added auth router - `backend/.env.example` - Environment variables documentation - `backend/tests/unit/test_auth_service.py` - Unit tests for auth service - `backend/tests/integration/test_auth_api.py` - Integration tests for auth endpoints **Frontend Files Created:** - `frontend/src/contexts/AuthContext.tsx` - Authentication context and state management - `frontend/src/components/auth/LoginForm.tsx` - Login form with validation - `frontend/src/components/auth/RegisterForm.tsx` - Registration with password strength - `frontend/src/components/auth/ForgotPasswordForm.tsx` - Password reset request - `frontend/src/components/auth/ResetPasswordForm.tsx` - Password reset confirmation - `frontend/src/components/auth/EmailVerification.tsx` - Email verification handler - `frontend/src/components/auth/ProtectedRoute.tsx` - Route protection wrapper - `frontend/src/components/auth/UserMenu.tsx` - User dropdown menu - `frontend/src/components/auth/index.ts` - Barrel export for auth components - `frontend/src/components/ui/dropdown-menu.tsx` - Radix dropdown component - `frontend/src/components/ui/avatar.tsx` - Radix avatar component - `frontend/src/pages/auth/LoginPage.tsx` - Login page layout - `frontend/src/pages/auth/RegisterPage.tsx` - Registration page layout - `frontend/src/pages/auth/ForgotPasswordPage.tsx` - Forgot password page - `frontend/src/pages/auth/ResetPasswordPage.tsx` - Reset password page - `frontend/src/pages/auth/EmailVerificationPage.tsx` - Email verification page - `frontend/src/pages/auth/index.ts` - Barrel export for auth pages - `frontend/src/services/apiClient.ts` - Updated with auth instance export - `frontend/src/App.tsx` - Updated with authentication routing **Database Migrations:** - `alembic/versions/xxxx_add_authentication_tables.py` - Users and auth tables migration ## QA Results _To be populated after QA review_