290 lines
12 KiB
Markdown
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_ |