Production-Ready Multi-Tenant FastAPI Template with Complete Authentication, Email Verification & Background Jobs
Features โข Installation โข API Docs โข Architecture โข Multi-Tenancy โข Contributing
A complete, production-ready FastAPI boilerplate featuring:
- ๐ข Multi-tenant SaaS architecture with organization management
- ๐ Comprehensive authentication - JWT, OAuth2 (Google & GitHub), Email verification with OTP
- ๐ง Email system - SMTP delivery, OTP codes, organization-aware templates
- โ๏ธ Background jobs - Celery with pause/resume control, scheduled tasks
- ๐ก๏ธ Enterprise security - Rate limiting, SQL injection protection, CORS, password hashing
- ๐๏ธ Modular architecture - Repository pattern, service layer, dependency injection
- ๐งช Complete testing - Unit & E2E test suite with mocked services
- ๐ณ Docker ready - Multi-service containerization with 8 services
Perfect for: SaaS applications, multi-tenant platforms, scalable APIs, production deployments
- โ JWT token-based authentication with configurable expiration
- โ User registration with email validation
- โ Secure password storage (Argon2 & bcrypt)
- โ OAuth2 password flow compliance
- โ Email verification with 6-digit OTP (24-hour expiry)
- โ Provider locking (email/password, Google, GitHub)
- โ Multi-organization support with invite tokens
- โ Organization-based tenant isolation
- โ Invite token system for joining organizations
- โ Same email across multiple organizations
- โ Cross-organization user management
- โ OAuth support for multi-org scenarios
- โ Organization context in all operations
- โ Google OAuth2 login with auto-profile extraction
- โ GitHub OAuth2 login with auto-profile extraction
- โ OAuth state management & CSRF protection
- โ Multi-org OAuth support
- โ Auto-verification for OAuth users
- โ Invite token OAuth flow
- โ SMTP email delivery (Gmail supported)
- โ Async task processing with Celery
- โ OTP verification emails
- โ Welcome emails with organization context
- โ Daily reminder emails for inactive users
- โ Customizable email templates
- โ Retry mechanism (3 attempts)
- โ Email queue with gevent pool (50 concurrent)
- โ Celery worker queues (email, maintenance)
- โ Scheduled tasks with Celery Beat
- โ Pause/Resume control per task type
- โ Flower monitoring dashboard
- โ Redis message broker
- โ Automatic cleanup (15+ day old tasks)
- โ Daily reminder scheduling
- โ Rate limiting (5-10 req/min, configurable)
- โ SQL injection protection middleware
- โ CORS configuration with origin validation
- โ Password strength validation
- โ Secure session management
- โ XSS prevention
- โ OTP expiration & single-use validation
- โ Multi-tenant data isolation
- โ Modular structure with clean separation
- โ Repository pattern for data access
- โ Service layer for business logic
- โ Dependency injection setup
- โ Environment-based configuration
- โ Database migrations (Alembic)
- โ Type hints throughout (Pydantic)
- โ Custom error handlers
- โ Complete test suite (Unit + E2E)
- โ Pytest with fixtures
- โ Test database isolation (automatically deleted after tests)
- โ Mocked external services
- โ Coverage reporting
- โ Shared conftest configuration
| Category | Technology | Purpose |
|---|---|---|
| Framework | FastAPI 0.135+ | High-performance async API |
| ORM | SQLAlchemy 2.0 | Database abstraction layer |
| Database | PostgreSQL 13+ | Relational data storage |
| Cache/Queue | Redis 7+ | Celery message broker |
| Tasks | Celery 5.6+ | Async background jobs |
| Auth | Python-JOSE, Authlib | JWT & OAuth2 handling |
| Hashing | Argon2, Bcrypt, Passlib | Secure password storage |
| smtplib, SMTP | Email delivery | |
| Rate Limit | SlowAPI, Limits | Request throttling |
| Validation | Pydantic 2.12+ | Request/response validation |
| Server | Uvicorn | ASGI server |
| Migrations | Alembic | Database versioning |
| Monitoring | Flower | Celery task monitoring |
| Testing | Pytest, Pytest-Cov | Unit & E2E testing |
| Container | Docker, Docker Compose | Multi-service deployment |
fastapi-saas-boilerplate/
โ
โโโ ๐ app/ # Backend - FastAPI application
โ โโโ ๐ core/ # Core functionality
โ โ โโโ ๐ celery/ # Celery configuration & tasks
โ โ โโโ ๐ config/ # Settings & configuration
โ โ โโโ ๐ database/ # Database connection & session
โ โ โโโ ๐ dependencies/ # Dependency injection
โ โ โโโ ๐ errors/ # Custom error handlers
โ โ โโโ ๐ middleware/ # Custom middleware (CORS, rate limit, etc.)
โ โ โโโ ๐ security/ # Auth handlers (OAuth, JWT)
โ โ
โ โโโ ๐ modules/ # Feature modules
โ โ โโโ ๐ auth/ # Authentication module
โ โ โ โโโ models/ # OTP model
โ โ โ โโโ repository/ # Data access
โ โ โ โโโ router/ # API endpoints
โ โ โ โโโ schema/ # Pydantic models
โ โ โ โโโ services/ # Business logic
โ โ โ
โ โ โโโ ๐ jobs/ # Background jobs module
โ โ โ โโโ models/ # Task control model
โ โ โ โโโ repository/ # Job data access
โ โ โ โโโ router/ # Job management routes
โ โ โ โโโ schema/ # Job schemas
โ โ โ โโโ services/ # Job control services
โ โ โ
โ โ โโโ ๐ organizations/ # Multi-tenant organization
โ โ โ โโโ models/ # Organization models
โ โ โ โโโ repository/ # Organization data access
โ โ โ โโโ router/ # Organization routes
โ โ โ โโโ schema/ # Organization schemas
โ โ โ โโโ services/ # Organization logic
โ โ โ
โ โ โโโ ๐ users/ # Users module
โ โ โโโ models/ # User database model
โ โ โโโ repository/ # User data access
โ โ โโโ router/ # User API endpoints
โ โ โโโ schema/ # User schemas
โ โ โโโ services/ # User business logic
โ โ
โ โโโ ๐ shared/ # Shared utilities
โ โ โโโ ๐ constants/ # Application constants
โ โ โโโ ๐ utils/ # Utility functions
โ โ โโโ ๐ validator/ # Custom validators
โ โ
โ โโโ ๐ templates/ # Email templates
โ โ โโโ ๐ emails/ # Email templates
โ โ
โ โโโ main.py # Application entry point
โ
โโโ ๐ frontend/ # Frontend - React application
โ โโโ ๐ public/ # Static assets
โ โโโ ๐ src/
โ โ โโโ ๐ api/ # API integration layer
โ โ โโโ ๐ components/ # Reusable components
โ โ โโโ ๐ pages/ # Page components
โ โ โโโ ๐ context/ # React Context (auth, org)
โ โ โโโ ๐ utils/ # Utility functions
โ โ โโโ App.jsx # Root component
โ โ โโโ index.js # Entry point
โ โ
โ โโโ package.json # Frontend dependencies
โ โโโ vite.config.js # Vite configuration
โ
โโโ ๐ tests/ # Test suite
โ โโโ conftest.py # Shared test fixtures
โ โโโ test_auth.py # Authentication tests
โ โโโ test_organizations.py # Organization tests
โ โโโ test_jobs.py # Job control tests
โ โโโ test_users.py # User tests
โ
โโโ ๐ migrations/ # Alembic migrations
โ โโโ versions/ # Migration versions
โ
โโโ .env.example # Environment template
โโโ docker-compose.yml # Docker orchestration
โโโ Dockerfile # Backend container
โโโ requirements.txt # Python dependencies
โโโ README.md # This file
graph TB
subgraph "Client Layer"
A[React Frontend]
end
subgraph "API Layer"
B[FastAPI Application]
C[Uvicorn Server]
end
subgraph "Authentication"
D[JWT Handler]
E[OAuth2 Provider]
F[OTP Service]
end
subgraph "Data Layer"
G[PostgreSQL]
H[Redis Cache]
end
subgraph "Background Processing"
I[Celery Workers]
J[Celery Beat Scheduler]
K[Flower Monitor]
end
subgraph "External Services"
L[SMTP Server]
M[Google OAuth]
N[GitHub OAuth]
end
A -->|HTTP/REST| B
B --> C
B --> D
B --> E
B --> F
B --> G
B --> H
B --> I
I --> H
J --> I
I --> L
E --> M
E --> N
K -.->|Monitor| I
style A fill:#61dafb
style B fill:#009688
style G fill:#336791
style H fill:#dc382d
style I fill:#37814a
sequenceDiagram
participant U as User
participant F as Frontend
participant A as API
participant DB as Database
participant R as Redis
participant C as Celery
U->>F: Register/Login
F->>A: POST /auth/register
A->>DB: Create User + Organization
A->>C: Queue OTP Email
C->>U: Send Email
A-->>F: Return Tokens
U->>F: Verify Email
F->>A: POST /auth/verify-email
A->>DB: Mark Email Verified
A->>R: Cache User Session
A-->>F: Success
U->>F: Create Organization
F->>A: POST /organizations/
A->>DB: Create Organization
A->>DB: Link User to Org
A-->>F: Organization Data
U->>F: Invite User to Org
F->>A: POST /organizations/{id}/invite
A->>DB: Create Invite Token
A->>C: Queue Invite Email
C->>U: Send Invite
A-->>F: Invite Token
graph LR
A[HTTP Request] --> B[CORS Middleware]
B --> C[Rate Limiter]
C --> D[SQL Injection Check]
D --> E[Route Handler]
E --> F{Auth Required?}
F -->|Yes| G[JWT Validation]
F -->|No| H[Process Request]
G --> H
H --> I[Service Layer]
I --> J[Repository Layer]
J --> K[Database]
K --> J
J --> I
I --> L[Response]
L --> M[JSON Serialization]
M --> N[HTTP Response]
- Python 3.8+
- PostgreSQL 13+
- Redis 7+
- Node.js 16+ (for frontend)
- Docker & Docker Compose (optional)
git clone https://github.com/yourusername/fastapi-saas-boilerplate.git
cd fastapi-saas-boilerplate# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Copy environment template
cp .env.example .env
# Edit .env with your configuration
nano .envUpdate .env file with your settings:
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/saas_db
# JWT
SECRET_KEY=your-secret-key-here
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
# OAuth (Optional)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-secret
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-secret
# Email (Gmail Example)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=your-email@gmail.com
SMTP_PASSWORD=your-app-password
SENDER_EMAIL=your-email@gmail.com
# Redis
REDIS_URL=redis://localhost:6379/0
# Celery
CELERY_BROKER_URL=redis://localhost:6379/0
CELERY_RESULT_BACKEND=redis://localhost:6379/0
# Frontend URL
FRONTEND_URL=http://localhost:5173# Start PostgreSQL and Redis (if not running)
# Then run migrations
alembic upgrade head# Terminal 1: FastAPI server
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
# Terminal 2: Celery worker
celery -A app.core.celery.celery_app worker --loglevel=info
# Terminal 3: Celery beat (scheduler)
celery -A app.core.celery.celery_app beat --loglevel=info
# Terminal 4: Flower (monitoring - optional)
celery -A app.core.celery.celery_app flower --port=5555cd frontend
npm install
npm run devAccess Points:
- Frontend: http://localhost:5173
- Backend API: http://localhost:8000
- API Docs: http://localhost:8000/docs
- Flower Dashboard: http://localhost:5555
git clone https://github.com/yourusername/fastapi-saas-boilerplate.git
cd fastapi-saas-boilerplate
cp .env.example .env
# Edit .env with your settingsdocker-compose up -dThis starts 8 services:
backend- FastAPI applicationfrontend- React applicationpostgres- PostgreSQL databaseredis- Redis cache/brokercelery-worker- Background task processorcelery-beat- Task schedulerflower- Celery monitoringnginx- Reverse proxy (optional)
docker-compose exec backend alembic upgrade head- Frontend: http://localhost:3000
- Backend: http://localhost:8000
- API Docs: http://localhost:8000/docs
- Flower: http://localhost:5555
# All services
docker-compose logs -f
# Specific service
docker-compose logs -f backend
docker-compose logs -f celery-workerdocker-compose down # Stop containers
docker-compose down -v # Stop and remove volumes (deletes data)Each organization is a tenant with isolated data:
class Organization(Base):
id: UUID # Unique identifier
name: str # Organization name
created_at: datetime # Creation timestamp
invite_token: str # Join token
users: List[User] # Associated usersgraph TD
A[User Signs Up] --> B{Invite Token?}
B -->|Yes| C[Join Existing Org]
B -->|No| D[Create New Org]
C --> E[Add to Organization]
D --> F[Become Org Owner]
E --> G[Email Verification]
F --> G
G --> H{Email Verified?}
H -->|Yes| I[Access Dashboard]
H -->|No| J[Pending Verification]
J --> K[Receive OTP Email]
K --> L[Enter OTP]
L --> I
- Same Email, Multiple Orgs: A user with
user@example.comcan exist in Organization A and Organization B - Invite Tokens: Each organization has a unique invite token for new members
- OAuth Multi-Org: OAuth users can join multiple organizations
- Data Isolation: Users see only data from their current organization context
POST /api/v1/organizations/
{
"name": "Acme Corp"
}
Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Corp",
"invite_token": "acmecorp-a1b2c3",
"created_at": "2024-01-15T10:30:00"
}POST /api/v1/auth/register
{
"email": "user@example.com",
"password": "SecurePass123!",
"full_name": "John Doe",
"invite_token": "acmecorp-a1b2c3"
}GET /api/v1/organizations/my-organizations
Response:
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Acme Corp",
"role": "owner"
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Beta Inc",
"role": "member"
}
]| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /api/v1/auth/register |
Register new user | No |
| POST | /api/v1/auth/login |
Login with credentials | No |
| POST | /api/v1/auth/verify-email |
Verify email with OTP | No |
| POST | /api/v1/auth/resend-otp |
Resend verification OTP | No |
| GET | /api/v1/auth/me |
Get current user info | Yes |
| POST | /api/v1/auth/logout |
Logout user | Yes |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /api/v1/auth/google/login |
Initiate Google OAuth | No |
| GET | /api/v1/auth/google/callback |
Google OAuth callback | No |
| GET | /api/v1/auth/github/login |
Initiate GitHub OAuth | No |
| GET | /api/v1/auth/github/callback |
GitHub OAuth callback | No |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /api/v1/organizations/ |
Create organization | Yes |
| GET | /api/v1/organizations/ |
List all organizations | Yes |
| GET | /api/v1/organizations/{id} |
Get organization details | Yes |
| PUT | /api/v1/organizations/{id} |
Update organization | Yes |
| DELETE | /api/v1/organizations/{id} |
Delete organization | Yes |
| GET | /api/v1/organizations/my-organizations |
Get user's organizations | Yes |
| POST | /api/v1/organizations/{id}/invite |
Generate invite token | Yes |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /api/v1/users/ |
List users | Yes |
| GET | /api/v1/users/{id} |
Get user details | Yes |
| PUT | /api/v1/users/{id} |
Update user | Yes |
| DELETE | /api/v1/users/{id} |
Delete user | Yes |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /api/v1/jobs/pause |
Pause background tasks | Yes |
| POST | /api/v1/jobs/resume |
Resume background tasks | Yes |
| GET | /api/v1/jobs/status |
Get task status | Yes |
| GET | /api/v1/jobs/cleanup |
Trigger cleanup job | Yes |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /health |
Health check | No |
| GET | /docs |
API documentation | No |
| GET | /redoc |
Alternative API docs | No |
- Enable 2-Factor Authentication in your Google account
- Generate App Password:
- Go to: https://myaccount.google.com/apppasswords
- Select "Mail" and your device
- Copy the 16-character password
- Update
.env:
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=your-email@gmail.com
SMTP_PASSWORD=your-16-char-app-password
SENDER_EMAIL=your-email@gmail.comLocated in app/templates/emails/:
otp_email.html- Email verification OTPwelcome_email.html- Welcome message after registrationreminder_email.html- Daily inactive user reminder
Edit HTML templates to match your brand:
<!-- app/templates/emails/otp_email.html -->
<div style="font-family: Arial, sans-serif;">
<h1>Verify Your Email</h1>
<p>Your verification code is: <strong>{{ otp_code }}</strong></p>
<p>Valid for 24 hours.</p>
</div>-
Email Queue (
email_queue)- OTP verification emails
- Welcome emails
- Organization invite emails
- Retry: 3 attempts with exponential backoff
-
Maintenance Queue (
maintenance_queue)- Database cleanup (15+ day old tasks)
- Scheduled daily reminders
- System health checks
# Start worker with specific queue
celery -A app.core.celery.celery_app worker -Q email_queue --loglevel=info
# Start all queues
celery -A app.core.celery.celery_app worker --loglevel=info# Daily cleanup at 2 AM
@celery_app.task
def cleanup_old_tasks():
"""Delete tasks older than 15 days"""
# Implementation in app/core/celery/tasks/maintenance.py
# Daily reminder at 10 AM
@celery_app.task
def send_daily_reminders():
"""Send reminders to inactive users"""
# Implementation in app/core/celery/tasks/email.py# Pause email tasks
POST /api/v1/jobs/pause
{
"task_type": "email"
}
# Resume email tasks
POST /api/v1/jobs/resume
{
"task_type": "email"
}
# Check status
GET /api/v1/jobs/statusAccess Celery task dashboard:
# Local: http://localhost:5555
# Docker: http://localhost:5555
# View:
# - Active tasks
# - Completed tasks
# - Failed tasks
# - Worker status
# - Task history- Argon2 hashing (primary)
- Bcrypt fallback support
- Minimum 8 characters
- Requires: uppercase, lowercase, number, special character
# Default limits
- Login: 5 requests/minute
- Register: 3 requests/minute
- Email sending: 10 requests/minute
- API endpoints: 100 requests/minuteConfigure in app/core/middleware/rate_limiter.py
Custom middleware checks all requests for SQL injection patterns:
# Blocked patterns
UNION, SELECT, DROP, INSERT, UPDATE, DELETE, --, /*# Allowed origins (production)
origins = [
"https://yourdomain.com",
"https://app.yourdomain.com"
]
# Development
origins = ["http://localhost:5173"]# Access token: 30 minutes (default)
# Refresh token: 7 days (optional)
# Algorithm: HS256
# Secret: Environment variable SECRET_KEY# Run all tests
pytest
# Run with coverage
pytest --cov=app --cov-report=html
# Run specific test file
pytest tests/test_auth.py
# Run with verbose output
pytest -v
# Run and show print statements
pytest -s- Automatic Setup: Test database created before each test session
- Isolation: Each test runs in a transaction that's rolled back
- Cleanup: Test database is automatically deleted after all tests complete
- Mocked Services: Email, OAuth, and external APIs are mocked
# tests/conftest.py - Shared fixtures
@pytest.fixture
def test_db():
"""Create test database and clean up after"""
# Setup
yield db
# Teardown - database deleted here
@pytest.fixture
def test_client():
"""FastAPI test client"""
return TestClient(app)
# tests/test_auth.py - Authentication tests
def test_register_user(test_client):
response = test_client.post("/api/v1/auth/register", json={
"email": "test@example.com",
"password": "SecurePass123!",
"full_name": "Test User"
})
assert response.status_code == 201# Generate HTML coverage report
pytest --cov=app --cov-report=html
# Open in browser
open htmlcov/index.html| Service | Port | Description |
|---|---|---|
| backend | 8000 | FastAPI application |
| frontend | 3000 | React application |
| postgres | 5432 | PostgreSQL database |
| redis | 6379 | Redis cache & message broker |
| celery-worker | - | Background task processor |
| celery-beat | - | Task scheduler |
| flower | 5555 | Celery monitoring dashboard |
| nginx | 80 | Reverse proxy (optional) |
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f backend
docker-compose logs -f celery-worker
# Restart a service
docker-compose restart backend
# Execute command in container
docker-compose exec backend alembic upgrade head
docker-compose exec backend pytest
# Stop all services
docker-compose down
# Remove volumes (deletes data)
docker-compose down -v
# Rebuild containers
docker-compose up -d --build# docker-compose.prod.yml
services:
backend:
environment:
- ENVIRONMENT=production
- DEBUG=false
deploy:
replicas: 3
restart_policy:
condition: on-failureError: could not connect to server: Connection refused
Solution:
# Check PostgreSQL is running
sudo service postgresql status
# Verify connection details in .env
DATABASE_URL=postgresql://user:password@localhost:5432/dbnameError: Error 111 connecting to localhost:6379. Connection refused.
Solution:
# Start Redis
sudo service redis-server start
# Verify Redis is running
redis-cli ping # Should return PONG# Check worker status
celery -A app.core.celery.celery_app inspect active
# Restart worker
# Kill existing workers
pkill -f 'celery worker'
# Start fresh worker
celery -A app.core.celery.celery_app worker --loglevel=infoCheck:
- SMTP credentials in
.env - Gmail App Password (not regular password)
- Celery worker is running
- Check Flower dashboard for failed tasks
# Reset migrations (CAUTION: deletes data)
alembic downgrade base
alembic upgrade head
# Create new migration
alembic revision --autogenerate -m "description"Check:
- Backend is running on port 8000
- CORS origins include frontend URL
VITE_API_URLin frontend.env
# Clean Docker cache
docker system prune -a
# Rebuild without cache
docker-compose build --no-cache
# Check logs
docker-compose logs backend- Multi-tenant architecture
- JWT authentication
- OAuth2 (Google & GitHub)
- Email verification with OTP
- Background job processing
- Rate limiting & security
- Docker deployment
- Complete test suite
- API documentation
- Password reset functionality
- User profile management
- Advanced role-based access control (RBAC)
- Organization settings & preferences
- Two-factor authentication (2FA)
- Webhooks support
- API key management
- Audit logging
- File upload service
- Notification system (push, SMS)
- Stripe payment integration
- Team member roles & permissions
- Activity dashboard
- Analytics & reporting
- GraphQL API support
- Kubernetes deployment configs
- CI/CD pipeline templates
- Mobile app (React Native)
- Multi-language support (i18n)
- Advanced monitoring & alerting
- Data export/import tools
- SSO (SAML, LDAP)
We welcome contributions! Here's how to get started:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests (
pytest) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow PEP 8 style guide
- Add type hints to all functions
- Write docstrings for modules, classes, and functions
- Maintain test coverage above 80%
- Update documentation for new features
All PRs must:
- Pass all existing tests
- Add tests for new features
- Maintain or improve code coverage
- Pass linting checks
This project is licensed under the MIT License - see the LICENSE file for details.
- FastAPI - Modern web framework
- SQLAlchemy - Database toolkit
- Celery - Distributed task queue
- Alembic - Database migrations
- Pydantic - Data validation
- Authlib - OAuth integration
- Documentation: API Docs
- Issues: GitHub Issues
- Email: support@yourdomain.com
Built with โค๏ธ using FastAPI
โญ Star this repo if you find it helpful!