Updated README.md
This commit is contained in:
587
README.md
587
README.md
@@ -1,104 +1,281 @@
|
||||
# MyAuth Module
|
||||
|
||||
A reusable, modular authentication system for FastAPI applications with pluggable database backends.
|
||||
A reusable, modular authentication system for FastAPI applications, designed for deployment on an internal PyPI server.
|
||||
|
||||
## 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.
|
||||
MyAuth provides a complete, 'out-of-the-box' authentication solution for your FastAPI projects. It's designed to be
|
||||
installed as a dependency and configured in just a few lines, letting you focus on your business logic instead of user
|
||||
and token management.
|
||||
|
||||
This module handles registration, login/logout, email verification, password reset, and token management (JWT & Refresh)
|
||||
with pluggable database backends.
|
||||
|
||||
## 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
|
||||
* **Complete Authentication:** User registration, email-based login, logout.
|
||||
* **Token Management:**
|
||||
* **JWT Access Tokens** (default: 30 min validity).
|
||||
* **Opaque Refresh Tokens** securely stored in the database (default: 7 days validity).
|
||||
* **User Lifecycle:**
|
||||
* Email verification (via JWT token).
|
||||
* Secure password reset (via secure token stored in DB).
|
||||
* Account activation / deactivation.
|
||||
* **Security:**
|
||||
* Password hashing with `bcrypt` (configurable rounds).
|
||||
* Strict password validation (uppercase, lowercase, digit, special character).
|
||||
* **Flexible Architecture:**
|
||||
* **Pluggable Backends:** Supports MongoDB, PostgreSQL, and SQLite out of the box.
|
||||
* **Abstract Email Service:** Use the built-in SMTP implementation or plug in your own (e.g., SendGrid, AWS SES).
|
||||
* **FastAPI Integration:**
|
||||
* A ready-to-use `APIRouter` that exposes all necessary endpoints under the `/auth` prefix.
|
||||
* Automatic handling of custom exceptions into correct HTTP responses.
|
||||
|
||||
### 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
|
||||
## Installation
|
||||
|
||||
### 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
|
||||
Install the base module and choose your "extras" based on your infrastructure.
|
||||
|
||||
## Project Structure
|
||||
```bash
|
||||
# Base installation (core logic, no DB or email drivers)
|
||||
pip install myauth --index-url [http://your-pypiserver.com/](http://your-pypiserver.com/)
|
||||
|
||||
```
|
||||
├──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
|
||||
# --- Installation with Extras (Recommended) ---
|
||||
|
||||
# To use with MongoDB
|
||||
pip install "myauth[mongodb]" --index-url [http://your-pypiserver.com/](http://your-pypiserver.com/)
|
||||
|
||||
# To use with PostgreSQL
|
||||
pip install "myauth[postgresql]" --index-url [http://your-pypiserver.com/](http://your-pypiserver.com/)
|
||||
|
||||
# To use the built-in SMTP email service
|
||||
pip install "myauth[email]" --index-url [http://your-pypiserver.com/](http://your-pypiserver.com/)
|
||||
|
||||
# To combine extras (e.g., PostgreSQL + Email)
|
||||
pip install "myauth[postgresql,email]" --index-url [http://your-pypiserver.com/](http://your-pypiserver.com/)
|
||||
```
|
||||
|
||||
## User Model
|
||||
### Core Dependencies
|
||||
|
||||
```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
|
||||
The core module requires: fastapi, pydantic, pydantic-settings, python-jose[cryptography], passlib[bcrypt],
|
||||
python-multipart
|
||||
|
||||
## Quick Start
|
||||
|
||||
To get started, choose one of the database options below. Each example is complete and self-contained: it sets up the
|
||||
FastAPI app, the authentication service, and the related routes.
|
||||
|
||||
Copy-paste the example that matches your infrastructure into your main.py.
|
||||
|
||||
### Option 1: Quick Start with MongoDB
|
||||
|
||||
This example configures myauth to use MongoDB as its backend.
|
||||
|
||||
```Python
|
||||
|
||||
from fastapi import FastAPI
|
||||
from my_auth import AuthService
|
||||
from my_auth.api import auth_router
|
||||
from my_auth.persistence.mongodb import MongoUserRepository, MongoTokenRepository
|
||||
|
||||
# 1. Initialize FastAPI app
|
||||
app = FastAPI()
|
||||
|
||||
# 2. Configure repositories for MongoDB
|
||||
# Make sure your connection string is correct
|
||||
user_repo = MongoUserRepository(connection_string="mongodb://localhost:27017/myappdb")
|
||||
token_repo = MongoTokenRepository(connection_string="mongodb://localhost:27017/myappdb")
|
||||
|
||||
# 3. Configure the Authentication Service
|
||||
# IMPORTANT: Change this to a long, random, secret string
|
||||
auth_service = AuthService(
|
||||
user_repository=user_repo,
|
||||
token_repository=token_repo,
|
||||
jwt_secret="YOUR_SUPER_LONG_AND_SECURE_JWT_SECRET_HERE"
|
||||
# email_service will be added in the next step
|
||||
)
|
||||
|
||||
# 4. Include the authentication routes
|
||||
# Endpoints like /auth/login, /auth/register are now active
|
||||
app.include_router(auth_router)
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"message": "Application running with MyAuth (MongoDB)"}
|
||||
```
|
||||
|
||||
## Token Management
|
||||
### Option 2: Quick Start with PostgreSQL
|
||||
|
||||
### Token Types
|
||||
The module uses a unified tokens collection with a discriminator field:
|
||||
This example configures myauth to use PostgreSQL as its backend.
|
||||
|
||||
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
|
||||
```Python
|
||||
|
||||
### Token Storage
|
||||
All tokens requiring storage (refresh and password reset) are kept in a single `tokens` collection/table with a `token_type` discriminator field.
|
||||
from fastapi import FastAPI
|
||||
from my_auth import AuthService
|
||||
from my_auth.api import auth_router
|
||||
from my_auth.persistence.postgresql import PostgreSQLUserRepository, PostgreSQLTokenRepository
|
||||
|
||||
## API Endpoints
|
||||
# 1. Initialize FastAPI app
|
||||
app = FastAPI()
|
||||
|
||||
The module exposes a pre-configured FastAPI router with the following endpoints:
|
||||
# 2. Configure repositories for PostgreSQL
|
||||
# Update with your database credentials
|
||||
db_config = {
|
||||
"host": "localhost",
|
||||
"port": 5432,
|
||||
"database": "mydb",
|
||||
"user": "postgres",
|
||||
"password": "secret"
|
||||
}
|
||||
user_repo = PostgreSQLUserRepository(**db_config)
|
||||
token_repo = PostgreSQLTokenRepository(**db_config)
|
||||
|
||||
# 3. Configure the Authentication Service
|
||||
# IMPORTANT: Change this to a long, random, secret string
|
||||
auth_service = AuthService(
|
||||
user_repository=user_repo,
|
||||
token_repository=token_repo,
|
||||
jwt_secret="YOUR_SUPER_LONG_AND_SECURE_JWT_SECRET_HERE"
|
||||
# email_service will be added in the next step
|
||||
)
|
||||
|
||||
# 4. Include the authentication routes
|
||||
# Endpoints like /auth/login, /auth/register are now active
|
||||
app.include_router(auth_router)
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"message": "Application running with MyAuth (PostgreSQL)"}
|
||||
```
|
||||
|
||||
### Option 3: Quick Start with SQLite
|
||||
|
||||
This example configures myauth to use SQLite, which is ideal for development or small applications.
|
||||
|
||||
```Python
|
||||
|
||||
from fastapi import FastAPI
|
||||
from my_auth import AuthService
|
||||
from my_auth.api import auth_router
|
||||
from my_auth.persistence.sqlite import SQLiteUserRepository, SQLiteTokenRepository
|
||||
|
||||
# 1. Initialize FastAPI app
|
||||
app = FastAPI()
|
||||
|
||||
# 2. Configure repositories for SQLite
|
||||
# This will create/use a file named 'auth.db' in the current directory
|
||||
db_path = "./auth.db"
|
||||
user_repo = SQLiteUserRepository(db_path=db_path)
|
||||
token_repo = SQLiteTokenRepository(db_path=db_path)
|
||||
|
||||
# 3. Configure the Authentication Service
|
||||
# IMPORTANT: Change this to a long, random, secret string
|
||||
auth_service = AuthService(
|
||||
user_repository=user_repo,
|
||||
token_repository=token_repo,
|
||||
jwt_secret="YOUR_SUPER_LONG_AND_SECURE_JWT_SECRET_HERE"
|
||||
# email_service will be added in the next step
|
||||
)
|
||||
|
||||
# 4. Include the authentication routes
|
||||
# Endpoints like /auth/login, /auth/register are now active
|
||||
app.include_router(auth_router)
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"message": "Application running with MyAuth (SQLite)"}
|
||||
```
|
||||
|
||||
## Next Step: Configure the Email Service
|
||||
|
||||
For email verification (/auth/verify-email) and password resets (/auth/password-reset) to work, you must provide an
|
||||
email service to the AuthService.
|
||||
|
||||
Simply modify the AuthService initialization from the Quick Start step you chose.
|
||||
|
||||
### Option 1: Use the Built-in SMTP Service
|
||||
|
||||
This is the simplest option if you have an SMTP server (like Gmail, SendGrid SMTP, etc.). Remember to install the extra:
|
||||
pip install "myauth[email]"
|
||||
|
||||
```Python
|
||||
|
||||
# ... (keep your app and repository config from the Quick Start)
|
||||
|
||||
from my_auth.email.smtp import SMTPEmailService
|
||||
|
||||
# 1. Configure the email service
|
||||
email_service = SMTPEmailService(
|
||||
host="smtp.gmail.com",
|
||||
port=587,
|
||||
username="your-email@gmail.com",
|
||||
password="your-app-password", # Use an 'App Password' for Gmail
|
||||
use_tls=True
|
||||
)
|
||||
|
||||
# 2. Pass the email service to AuthService
|
||||
auth_service = AuthService(
|
||||
user_repository=user_repo, # From Quick Start
|
||||
token_repository=token_repo, # From Quick Start
|
||||
email_service=email_service, # Add this line
|
||||
jwt_secret="YOUR_SUPER_LONG_AND_SECURE_JWT_SECRET_HERE"
|
||||
)
|
||||
|
||||
# ... (keep 'app.include_router(auth_router)')
|
||||
```
|
||||
|
||||
### Option 2: Create a Custom Email Service
|
||||
|
||||
If you use a third-party service (like AWS SES, Mailgun) that requires an API, you can implement your own.
|
||||
|
||||
```Python
|
||||
|
||||
# ... (keep your app and repository config from the Quick Start)
|
||||
|
||||
from my_auth.email.base import EmailService
|
||||
|
||||
|
||||
# 1. Implement your custom email service
|
||||
class CustomEmailService(EmailService):
|
||||
def __init__(self, api_key: str):
|
||||
# self.api_key = api_key
|
||||
# self.client = ThirdPartyClient(api_key=api_key)
|
||||
print("Custom Email Service Initialized")
|
||||
|
||||
def send_verification_email(self, email: str, token: str) -> None:
|
||||
# Your custom logic to send an email via an API
|
||||
# verification_link = f"http://localhost:8000/verify?token={token}"
|
||||
print(f"Sending VERIFICATION to {email} with token {token}")
|
||||
pass
|
||||
|
||||
def send_password_reset_email(self, email: str, token: str) -> None:
|
||||
# Your custom logic to send an email via an API
|
||||
# reset_link = f"http://localhost:8000/reset-password?token={token}"
|
||||
print(f"Sending PASSWORD RESET to {email} with token {token}")
|
||||
pass
|
||||
|
||||
|
||||
# 2. Initialize your custom service
|
||||
email_service = CustomEmailService(api_key="YOUR_API_KEY_HERE")
|
||||
|
||||
# 3. Pass your custom service to AuthService
|
||||
auth_service = AuthService(
|
||||
user_repository=user_repo, # From Quick Start
|
||||
token_repository=token_repo, # From Quick Start
|
||||
email_service=email_service, # Add this line
|
||||
jwt_secret="YOUR_SUPER_LONG_AND_SECURE_JWT_SECRET_HERE"
|
||||
)
|
||||
|
||||
# ... (keep 'app.include_router(auth_router)')
|
||||
```
|
||||
|
||||
## API Endpoints Reference
|
||||
|
||||
The `auth_router` exposes the following endpoints under the `/auth` prefix:
|
||||
|
||||
```
|
||||
POST /auth/register # User registration
|
||||
@@ -112,174 +289,124 @@ POST /auth/verify-email # Verify email with token
|
||||
GET /auth/me # Get current user info
|
||||
```
|
||||
|
||||
## Installation
|
||||
### Error Handling
|
||||
|
||||
### Dependencies
|
||||
The module uses custom exceptions that are automatically converted to the appropriate HTTP responses by FastAPI:
|
||||
|
||||
**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
|
||||
* `InvalidCredentialsError` → **401 Unauthorized**
|
||||
* `UserAlreadyExistsError` → **409 Conflict**
|
||||
* `UserNotFoundError` → **404 Not Found**
|
||||
* `InvalidTokenError` → **401 Unauthorized**
|
||||
* `RevokedTokenError` → **401 Unauthorized**
|
||||
* `ExpiredTokenError` → **401 Unauthorized**
|
||||
* `EmailNotVerifiedError` → **403 Forbidden (on login attempt)**
|
||||
* `AccountDisabledError` → **403 Forbidden (on login attempt)**
|
||||
|
||||
## Configuration Options
|
||||
|
||||
```python
|
||||
All options are passed during the `AuthService` initialization:
|
||||
|
||||
```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
|
||||
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
|
||||
## Appendix (Contributor & Development Details)
|
||||
|
||||
The module is fully testable with pytest. Test fixtures are provided for each database implementation.
|
||||
<details> <summary><b> Appendix A: Project Structure (src/my_auth)</b></summary>
|
||||
|
||||
```
|
||||
my_auth/
|
||||
├── __init__.py
|
||||
├── models/ # Pydantic models (User, Token...)
|
||||
│ ├── user.py
|
||||
│ ├── token.py
|
||||
│ └── email_verification.py
|
||||
├── core/ # Business logic (Auth, Password, Token services)
|
||||
│ ├── auth.py
|
||||
│ ├── password.py
|
||||
│ └── token.py
|
||||
├── persistence/ # Database abstraction
|
||||
│ ├── base.py # Abstract base classes
|
||||
│ ├── mongodb.py
|
||||
│ ├── sqlite.py
|
||||
│ └── postgresql.py
|
||||
├── api/ # FastAPI routes
|
||||
│ └── routes.py
|
||||
├── email/ # Email service
|
||||
│ ├── base.py # Abstract interface
|
||||
│ └── smtp.py
|
||||
├── exceptions.py # Custom HTTP exceptions
|
||||
└── config.py # Configuration classes (if any)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details> <summary><b> Appendix B: Internal Data Models </b></summary>
|
||||
|
||||
### User Model
|
||||
|
||||
This is the internal Pydantic model used by the service.
|
||||
|
||||
```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
|
||||
|
||||
The module uses a unified `tokens` collection/table with a `token_type` discriminator field for all persistent tokens.
|
||||
|
||||
1. Access Token (JWT): 30 minutes validity, stateless, not stored in DB.
|
||||
1. Refresh Token (Opaque): 7 days validity, stored in DB.
|
||||
1. Password Reset Token (Random): 15 minutes validity, stored in DB.
|
||||
1. Email Verification Token (JWT): Stateless, not stored in DB.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<details> <summary><b> Appendix C: Testing & Security </b></summary>
|
||||
|
||||
### Testing
|
||||
|
||||
The module is testable with `pytest`.
|
||||
|
||||
```Bash
|
||||
|
||||
```bash
|
||||
pytest tests/
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
### 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
|
||||
* Passwords are hashed using bcrypt with configurable rounds.
|
||||
* JWT tokens are signed with HS256 (configurable).
|
||||
* Refresh tokens are opaque and stored securely in the database.
|
||||
* Password reset tokens are single-use, opaque, and expire quickly (15 min).
|
||||
* Rate Limiting is not included and should be implemented at the application level (e.g., using `slowapi`).
|
||||
* HTTPS should be enforced by the production web server (e.g., Nginx, Traefik).
|
||||
|
||||
## 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
|
||||
</details>
|
||||
|
||||
## License
|
||||
|
||||
[Your License Here]
|
||||
|
||||
## Contributing
|
||||
|
||||
[Your Contributing Guidelines Here]
|
||||
MIT
|
||||
|
||||
Reference in New Issue
Block a user