Files
MyAuth/README-dev.md
2025-10-18 22:42:22 +02:00

285 lines
9.5 KiB
Markdown

# MyAuth Module
A reusable, modular authentication system for FastAPI applications with pluggable database backends.
## Overview
This module provides a complete authentication solution designed to be deployed on internal PyPI servers and reused across multiple projects. It handles user registration, login/logout, token management, email verification, and password reset functionality.
## Features
### Core Authentication
- ✅ User registration with email and username
- ✅ Login/logout with email-based authentication
- ✅ JWT-based access tokens (30 minutes validity)
- ✅ Opaque refresh tokens stored in database (7 days validity)
- ✅ Password hashing with configurable bcrypt rounds
### User Management
- ✅ Email verification with JWT tokens
- ✅ Password reset with secure random tokens (15 minutes validity)
- ✅ User roles management (flexible, no predefined roles)
- ✅ User settings storage (dict field)
- ✅ Account activation/deactivation
### Password Security
- ✅ Strict password validation (via Pydantic):
- Minimum 8 characters
- At least 1 uppercase letter
- At least 1 lowercase letter
- At least 1 digit
- At least 1 special character
### Architecture
- ✅ Abstract base classes for database persistence
- ✅ Multiple database implementations: MongoDB, SQLite, PostgreSQL
- ✅ Abstract email service interface with optional SMTP implementation
- ✅ Custom exceptions with FastAPI integration
- ✅ Synchronous implementation
- ✅ Ready-to-use FastAPI router with `/auth` prefix
## Project Structure
```
├──src
│ my_auth/
│ ├── __init__.py
│ ├── models/ # Pydantic models
│ │ ├── user.py # User model with roles and settings
│ │ ├── token.py # Token models (access, refresh, reset)
│ │ └── email_verification.py # Email verification models
│ ├── core/ # Business logic
│ │ ├── auth.py # Authentication service
│ │ ├── password.py # Password hashing/verification
│ │ └── token.py # Token generation/validation
│ ├── persistence/ # Database abstraction
│ │ ├── base.py # Abstract base classes
│ │ ├── mongodb.py # MongoDB implementation
│ │ ├── sqlite.py # SQLite implementation
│ │ └── postgresql.py # PostgreSQL implementation
│ ├── api/ # FastAPI routes
│ │ └── routes.py # All authentication endpoints
│ ├── email/ # Email service
│ │ ├── base.py # Abstract interface
│ │ └── smtp.py # SMTP implementation (optional)
│ ├── exceptions.py # Custom exceptions
│ └── config.py # Configuration classes
├── tests
```
## User Model
```python
class User:
id: str # Unique identifier
email: str # Unique, required
username: str # Required, non-unique
hashed_password: str # Bcrypt hashed
roles: list[str] # Free-form roles, no defaults
user_settings: dict # Custom user settings
is_verified: bool # Email verification status
is_active: bool # Account active status
created_at: datetime
updated_at: datetime
```
## Token Management
### Token Types
The module uses a unified tokens collection with a discriminator field:
1. **Access Token (JWT)**: 30 minutes validity, stateless
2. **Refresh Token (Opaque)**: 7 days validity, stored in DB
3. **Password Reset Token (Random)**: 15 minutes validity, stored in DB
4. **Email Verification Token (JWT)**: Stateless, no DB storage
### Token Storage
All tokens requiring storage (refresh and password reset) are kept in a single `tokens` collection/table with a `token_type` discriminator field.
## API Endpoints
The module exposes a pre-configured FastAPI router with the following endpoints:
```
POST /auth/register # User registration
POST /auth/login # Login (email + password)
POST /auth/logout # Logout (revokes refresh token)
POST /auth/refresh # Refresh access token
POST /auth/password-reset-request # Request password reset
POST /auth/password-reset # Reset password with token
POST /auth/verify-email-request # Request email verification
POST /auth/verify-email # Verify email with token
GET /auth/me # Get current user info
```
## Installation
### Dependencies
**Core dependencies:**
```bash
pip install fastapi pydantic pydantic-settings python-jose[cryptography] passlib[bcrypt] python-multipart
```
**Database-specific dependencies:**
- MongoDB: `pip install pymongo`
- SQLite: Built-in (no additional dependency)
- PostgreSQL: `pip install psycopg2-binary`
**Optional email dependency:**
- SMTP: `pip install secure-smtplib`
## Usage
### Basic Setup
```python
from fastapi import FastAPI
from auth_module import AuthService
from auth_module.persistence.mongodb import MongoUserRepository, MongoTokenRepository
from auth_module.api import auth_router
# Initialize repositories
user_repo = MongoUserRepository(connection_string="mongodb://localhost:27017/mydb")
token_repo = MongoTokenRepository(connection_string="mongodb://localhost:27017/mydb")
# Initialize auth service
auth_service = AuthService(
user_repository=user_repo,
token_repository=token_repo,
jwt_secret="your-secret-key-here",
access_token_expire_minutes=30,
refresh_token_expire_days=7,
password_reset_token_expire_minutes=15,
password_hash_rounds=12
)
# Create FastAPI app and include auth router
app = FastAPI()
app.include_router(auth_router) # Mounts at /auth prefix
```
### Using Different Databases
#### SQLite
```python
from auth_module.persistence.sqlite import SQLiteUserRepository, SQLiteTokenRepository
user_repo = SQLiteUserRepository(db_path="./auth.db")
token_repo = SQLiteTokenRepository(db_path="./auth.db")
```
#### PostgreSQL
```python
from auth_module.persistence.postgresql import PostgreSQLUserRepository, PostgreSQLTokenRepository
user_repo = PostgreSQLUserRepository(
host="localhost",
port=5432,
database="mydb",
user="postgres",
password="secret"
)
token_repo = PostgreSQLTokenRepository(...)
```
### Email Service Configuration
```python
from auth_module.email.smtp import SMTPEmailService
email_service = SMTPEmailService(
host="smtp.gmail.com",
port=587,
username="your-email@gmail.com",
password="your-app-password",
use_tls=True
)
auth_service = AuthService(
user_repository=user_repo,
token_repository=token_repo,
email_service=email_service, # Optional
...
)
```
### Custom Email Service
Implement your own email service by extending the abstract base class:
```python
from auth_module.email.base import EmailService
class CustomEmailService(EmailService):
def send_verification_email(self, email: str, token: str) -> None:
# Your implementation (SendGrid, AWS SES, etc.)
pass
def send_password_reset_email(self, email: str, token: str) -> None:
# Your implementation
pass
```
## Error Handling
The module uses custom exceptions that are automatically converted to appropriate HTTP responses:
- `InvalidCredentialsError` → 401 Unauthorized
- `UserAlreadyExistsError` → 409 Conflict
- `UserNotFoundError` → 404 Not Found
- `InvalidTokenError` → 401 Unauthorized
- `RevokedTokenError` → 401 Unauthorized
- `ExpiredTokenError` → 401 Unauthorized
- `EmailNotVerifiedError` → 403 Forbidden
- `AccountDisabledError` → 403 Forbidden
## Configuration Options
```python
AuthService(
user_repository: UserRepository, # Required
token_repository: TokenRepository, # Required
jwt_secret: str, # Required
jwt_algorithm: str = "HS256", # Optional
access_token_expire_minutes: int = 30, # Optional
refresh_token_expire_days: int = 7, # Optional
password_reset_token_expire_minutes: int = 15, # Optional
password_hash_rounds: int = 12, # Optional (bcrypt cost)
email_service: EmailService = None # Optional
)
```
## Testing
The module is fully testable with pytest. Test fixtures are provided for each database implementation.
```bash
pytest tests/
```
## Security Considerations
- Passwords are hashed using bcrypt with configurable rounds
- JWT tokens are signed with HS256 (configurable)
- Refresh tokens are opaque and stored securely
- Password reset tokens are single-use and expire after 15 minutes
- Email verification tokens are stateless JWT
- Rate limiting should be implemented at the application level
- HTTPS should be enforced by the application
## Future Enhancements (Not Included)
- Multi-factor authentication (2FA/MFA)
- Rate limiting on login attempts
- OAuth2 provider integration
- Session management (multiple device tracking)
- Account lockout after failed attempts
## License
[Your License Here]
## Contributing
[Your Contributing Guidelines Here]