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

9.5 KiB

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

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:

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

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

from auth_module.persistence.sqlite import SQLiteUserRepository, SQLiteTokenRepository

user_repo = SQLiteUserRepository(db_path="./auth.db")
token_repo = SQLiteTokenRepository(db_path="./auth.db")

PostgreSQL

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

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:

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

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.

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]