youtube-summarizer/docs/stories/3.1.user-authentication-sys...

290 lines
12 KiB
Markdown

# 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<void>;
register: (email: string, password: string) => Promise<void>;
logout: () => void;
refreshToken: () => Promise<void>;
}
```
### 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_