9.9 KiB
Authy2 Backend - Architecture Documentation
Overview
This document describes the architecture and design decisions for the Authy2 backend authentication and authorization API.
Architecture Pattern
The application follows a layered architecture pattern with clear separation of concerns:
┌─────────────────────────────────────┐
│ API Layer (Routes) │ Flask blueprints, request validation
├─────────────────────────────────────┤
│ Service Layer (Business) │ Business logic, orchestration
├─────────────────────────────────────┤
│ Data Layer (Models) │ ORM models, database access
├─────────────────────────────────────┤
│ Database (PostgreSQL) │ Data persistence
└─────────────────────────────────────┘
Key Principles
- Separation of Concerns: Each layer has distinct responsibilities
- Dependency Injection: Extensions initialized separately
- Factory Pattern: Application factory for flexible configuration
- Repository Pattern: Service layer abstracts data access
- Single Responsibility: Each module has one reason to change
Component Structure
1. Application Factory (app/__init__.py)
Implements the factory pattern for creating Flask applications with different configurations.
Responsibilities:
- Initialize Flask app
- Load configuration
- Initialize extensions
- Register blueprints
- Setup middleware
- Register error handlers
2. Models Layer (app/models/)
SQLAlchemy ORM models representing the database schema.
Key Models:
User: User accountsOrganization: Multi-tenant organizationsOrganizationMember: User-organization membershipAuthenticationMethod: Multi-method authenticationSession: User session managementAuditLog: Activity trackingOIDCClient: OAuth2/OIDC clients
Base Model Features:
- UUID primary keys
- Timestamps (created_at, updated_at)
- Soft delete (deleted_at)
- Common methods (save, delete, update, to_dict)
3. Service Layer (app/services/)
Contains business logic and orchestrates data access.
Services:
AuthService: Authentication operationsUserService: User managementOrganizationService: Organization managementSessionService: Session managementAuditService: Audit logging
Benefits:
- Keeps controllers thin
- Testable business logic
- Reusable across endpoints
- Transaction management
4. API Layer (app/api/)
Flask blueprints defining HTTP endpoints.
Structure:
- Versioned blueprints (
v1/, futurev2/) - RESTful design
- Request validation with Marshmallow
- Response formatting
Endpoint Groups:
auth.py: Authentication endpointsusers.py: User profile endpointsorganizations.py: Organization CRUD
5. Schemas (app/schemas/)
Marshmallow schemas for validation and serialization.
Types:
- Input validation schemas
- Output serialization schemas
- Nested schemas for relationships
6. Middleware (app/middleware/)
Request/response middleware components.
Components:
RequestIDMiddleware: Request tracingSecurityHeadersMiddleware: Security headersCORS: Cross-origin resource sharing
7. Exceptions (app/exceptions/)
Custom exception hierarchy for API errors.
Hierarchy:
BaseAPIException
├── UnauthorizedError (401)
├── ForbiddenError (403)
├── ValidationError (400)
├── NotFoundError (404)
└── ConflictError (409)
8. Utilities (app/utils/)
Shared utilities and helpers.
Components:
response.py: Standardized API responsesconstants.py: Enums and constantsdecorators.py: Authentication decorators
Data Models
User Model
User
├── id: UUID (PK)
├── email: String (unique)
├── email_verified: Boolean
├── full_name: String
├── status: Enum (active, inactive, suspended)
├── last_login_at: DateTime
└── relationships:
├── authentication_methods
├── sessions
├── organization_memberships
└── audit_logs
Organization Model
Organization
├── id: UUID (PK)
├── name: String
├── slug: String (unique)
├── description: Text
├── is_active: Boolean
├── settings: JSON
└── relationships:
├── members (OrganizationMember)
└── oidc_clients
Authentication Method Model
AuthenticationMethod
├── id: UUID (PK)
├── user_id: UUID (FK)
├── method_type: Enum (password, google, github, oidc)
├── password_hash: String (for password auth)
├── provider_user_id: String (for OAuth)
├── provider_data: JSON
└── is_primary: Boolean
Security Architecture
Authentication Flow
- User submits credentials
AuthService.authenticate()validates credentials- Session created with secure token
- Token stored in Redis
- Session ID returned to client
- Subsequent requests authenticated via session
Authorization Flow
- Request includes session token
@login_requireddecorator validates session- User loaded into
g.current_user @require_rolechecks organization permissions- Request proceeds or returns 403
Password Security
- Bcrypt hashing (12+ rounds in production)
- Configurable rounds per environment
- No plain-text passwords stored
- Password strength validation
Session Security
- Secure session tokens (32-byte random)
- Configurable expiration
- Session revocation support
- IP and user agent tracking
API Response Format
All responses follow a standardized envelope:
{
"version": "1.0",
"success": boolean,
"code": number,
"message": string,
"request_id": string,
"data": object | null,
"error": {
"type": string,
"details": object
} | null,
"meta": object | null
}
Benefits:
- Consistent client parsing
- Request tracing
- Error handling
- Pagination metadata
Database Design
Multi-Tenancy
Organizations provide multi-tenancy:
- Each org is isolated
- Users can belong to multiple orgs
- Role-based access per org
Audit Trail
Comprehensive logging:
- All mutations logged
- User context captured
- IP and user agent tracked
- Queryable history
Soft Deletes
All models support soft delete:
deleted_attimestamp- Allows recovery
- Maintains referential integrity
- Audit trail preserved
Configuration Management
Environment-based Config
config/
├── base.py # Common settings
├── development.py # Dev overrides
├── testing.py # Test config
└── production.py # Production settings
Configuration Hierarchy
- Base configuration
- Environment-specific overrides
- Environment variables (highest priority)
Testing Strategy
Unit Tests
- Test individual functions/methods
- Mock external dependencies
- Fast execution
- High coverage target (>80%)
Integration Tests
- Test API endpoints end-to-end
- Use test database
- Verify request/response flow
- Authentication flow testing
Test Fixtures
- Reusable test data
- Database setup/teardown
- Authenticated clients
- Sample users/organizations
Deployment Architecture
Recommended Setup
┌─────────────┐
│ Load │
│ Balancer │
└──────┬──────┘
│
┌───┴────┐
│ │
┌──▼──┐ ┌──▼──┐
│ Web │ │ Web │ Gunicorn workers
│ App │ │ App │
└──┬───┘ └──┬───┘
│ │
└────┬────┘
│
┌───▼────┐
│ Redis │ Session storage
└────────┘
│
┌───▼────────┐
│ PostgreSQL │ Data persistence
└────────────┘
Scaling Considerations
- Stateless application (sessions in Redis)
- Horizontal scaling via load balancer
- Database connection pooling
- Redis for distributed sessions
- Celery for background tasks (future)
Error Handling
Exception Hierarchy
All exceptions inherit from BaseAPIException:
- Consistent error responses
- HTTP status codes
- Error type categorization
- Detailed error information
Global Error Handlers
- Catch all exceptions
- Log errors appropriately
- Return standardized responses
- Never expose internals
Logging & Monitoring
Audit Logging
- User actions tracked
- Organization changes logged
- Authentication events
- Queryable audit trail
Application Logging
- Structured logging
- Request/response logging
- Error logging
- Performance metrics
Future Enhancements
- OAuth Provider: Implement full OAuth2/OIDC provider
- MFA: Multi-factor authentication
- Email Service: Email verification and notifications
- Webhooks: Event-driven notifications
- API Keys: Service account authentication
- Rate Limiting: Per-user/org rate limits
- Background Jobs: Celery integration
- Monitoring: Prometheus/Grafana metrics
Best Practices
- Always use service layer for business logic
- Validate all inputs with Marshmallow schemas
- Use decorators for authentication/authorization
- Log important events to audit log
- Follow RESTful conventions for endpoints
- Write tests for all new features
- Use transactions for multi-step operations
- Never return sensitive data without filtering
- Keep controllers thin - logic goes in services
- Version the API for backward compatibility