# Authy2 Backend - Authentication & Authorization API Production-ready Flask/SQLAlchemy API for authentication and authorization services. ## Features - ๐Ÿ” **Multi-method Authentication**: Password, OAuth (Google, GitHub, Microsoft), SAML, OIDC - ๐Ÿ‘ฅ **Multi-tenancy**: Organization-based access control with roles - ๐Ÿ”‘ **Session Management**: Secure session handling with Redis - ๐Ÿ“ **Audit Logging**: Comprehensive activity tracking - ๐Ÿ›ก๏ธ **Security**: Bcrypt password hashing, CORS, security headers, rate limiting - ๐Ÿ“Š **API Response Envelope**: Consistent response format across all endpoints - โœ… **Validation**: Marshmallow schemas for request/response validation - ๐Ÿงช **Testing**: Comprehensive unit and integration tests - ๐Ÿ“š **Documentation**: OpenAPI/Swagger compatible ## Tech Stack - **Framework**: Flask 3.0 - **Database**: PostgreSQL with SQLAlchemy ORM - **Caching/Sessions**: Redis - **Validation**: Marshmallow - **Testing**: Pytest - **Security**: Flask-Bcrypt, Flask-CORS - **Migration**: Flask-Migrate (Alembic) ## Quick Start ### Prerequisites - Python 3.11+ - PostgreSQL 14+ - Redis 6+ ### Installation 1. **Clone the repository**: ```bash git clone cd authy2/backend ``` 2. **Create virtual environment**: ```bash python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate ``` 3. **Install dependencies**: ```bash pip install -r requirements/development.txt ``` 4. **Set up environment variables**: ```bash cp .env.example .env # Edit .env with your configuration ``` 5. **Initialize database**: ```bash python scripts/init_db.py ``` 6. **Seed sample data** (optional): ```bash python -m scripts.seed_data ``` 7. **Run the application**: ```bash flask run # Or in debug mode FLASK_ENV=development flask run --debug --port 5000 # Or using the WSGI file python wsgi.py ``` The API will be available at `http://localhost:5000` ## Docker Deployment ### Prerequisites - Docker 20.10+ - Docker Compose 2.0+ ### Quick Start 1. **Start all services**: ```bash docker-compose up -d ``` 2. **Initialize the database** (run migrations): ```bash docker-compose exec api python manage.py db upgrade ``` 3. **Seed sample data** (optional): ```bash docker-compose exec api python scripts/seed_data.py ``` 4. **Verify health**: ```bash curl http://localhost:5000/api/health ``` ### Useful Commands ```bash # View logs docker-compose logs -f api # Run migrations docker-compose exec api python manage.py db upgrade # Open shell in container docker-compose exec api /bin/bash # Rebuild after changes docker-compose up -d --build # Stop all services docker-compose down ``` ### Environment Variables Copy `.env.example` to `.env` and configure: - `POSTGRES_USER` / `POSTGRES_PASSWORD` - Database credentials - `SECRET_KEY` - Flask secret key (required in production) - `ENCRYPTION_KEY` - Data encryption key - `CA_ENCRYPTION_KEY` - CA private key encryption - `CORS_ORIGINS` - Allowed CORS origins (comma-separated) ### Production Considerations - Use a strong `SECRET_KEY` (256-bit random) - Enable HTTPS via nginx (configure SSL certificates) - Set `BCRYPT_LOG_ROUNDS=13` for stronger password hashing - Use Redis persistence (`--appendonly yes`) - Configure log aggregation as needed ## API Endpoints ### Authentication - `POST /api/v1/auth/register` - Register new user - `POST /api/v1/auth/login` - Login - `POST /api/v1/auth/logout` - Logout - `GET /api/v1/auth/me` - Get current user - `GET /api/v1/auth/sessions` - Get user sessions - `POST /api/v1/auth/sessions/refresh` - Extend session idle window - `DELETE /api/v1/auth/sessions/:id` - Revoke session ### Users - `GET /api/v1/users/me` - Get current user profile - `PATCH /api/v1/users/me` - Update profile - `DELETE /api/v1/users/me` - Delete account - `POST /api/v1/users/me/password` - Change password - `GET /api/v1/users/me/organizations` - Get user organizations ### Organizations - `POST /api/v1/organizations` - Create organization - `GET /api/v1/organizations/:id` - Get organization - `PATCH /api/v1/organizations/:id` - Update organization - `DELETE /api/v1/organizations/:id` - Delete organization - `GET /api/v1/organizations/:id/members` - Get members - `POST /api/v1/organizations/:id/members` - Add member - `DELETE /api/v1/organizations/:id/members/:userId` - Remove member - `PATCH /api/v1/organizations/:id/members/:userId/role` - Update role ### Contact (Public โ€” No Auth Required) - `POST /api/v1/contact` - Submit a contact enquiry (demo request, sales enquiry, general, or support). Rate limited to 5 requests per IP per hour. Sends an email to info@secuird.tech. ### Health - `GET /api/health` - Health check ## O-auth Setup - Redirect URI ```http://localhost:5000/api/v1/auth/external/[google|microsoft]/callback``` ## API Response Format All API responses follow the standardized envelope format: ```json { "version": "1.0", "success": true, "code": 200, "message": "Success message", "request_id": "uuid-v4", "data": {}, "meta": {} } ``` Error responses: ```json { "version": "1.0", "success": false, "code": 400, "message": "Error message", "request_id": "uuid-v4", "error": { "type": "VALIDATION_ERROR", "details": {} } } ``` ## Database Migrations Create a new migration: ```bash flask db migrate -m "Description of changes" ``` Apply migrations: ```bash flask db upgrade ``` Rollback: ```bash flask db downgrade ``` ### Environment Configuration - **Development**: `FLASK_ENV=development` - **Testing**: `FLASK_ENV=testing` - **Production**: `FLASK_ENV=production` ## Production Deployment ### Using Gunicorn ```bash pip install -r requirements/production.txt gunicorn -w 4 -b 0.0.0.0:8000 wsgi:app ``` ## Security Considerations - All passwords hashed with Bcrypt (12+ rounds in production) - CORS configured for allowed origins - Security headers enabled (CSP, HSTS, etc.) - Rate limiting on sensitive endpoints - SQL injection protection via SQLAlchemy ORM - Session management with secure cookies - Request ID tracking for audit trails ## Session Management Sessions are database-backed bearer tokens stored in PostgreSQL. Each session is created at login and validated on every authenticated request via the `login_required` decorator. ### Sliding Timeout Sessions use a **sliding window** model with two independent limits: | Timeout | Default | Env Var | Behaviour | |---------|---------|---------|-----------| | **Idle** | 15 min | `SESSION_IDLE_TIMEOUT` | Extends automatically on every request. If no request is made within this window the session expires. | | **Absolute** | 8 h | `SESSION_ABSOLUTE_TIMEOUT` | Hard cap measured from session creation. Activity cannot extend a session beyond this point. | Every authenticated request resets the idle clock by calling `Session.refresh()`, which sets `expires_at = now + idle_timeout` โ€” but never past `created_at + absolute_timeout`. This means: - An active user stays logged in indefinitely **up to** the absolute cap. - An idle user is logged out after the idle timeout. - No session can survive longer than the absolute timeout regardless of activity. ### Configuration Override defaults via environment variables: ```bash SESSION_IDLE_TIMEOUT=900 # seconds (15 min) SESSION_ABSOLUTE_TIMEOUT=28800 # seconds (8 h) ``` ### Cleanup Expired sessions are soft-marked as `EXPIRED` by the `cleanup_sessions` job. Run it periodically via the job runner: ```bash python manage.py cleanup_sessions # Or via the job runner (Docker): JOB_NAME=cleanup_sessions JOB_INTERVAL_SECONDS=300 ``` ### Session Endpoints - `GET /api/v1/auth/sessions` โ€” List active sessions for the current user - `POST /api/v1/auth/sessions/refresh` โ€” Extend the current session's idle window (returns new `expires_at`) - `DELETE /api/v1/auth/sessions/:id` โ€” Revoke a specific session # Boostrap db python manage.py db upgrade ## Development Commands ### Run Flask in Development ```bash FLASK_ENV=development flask run --debug --port 8888 ``` ### Seed Sample Data ```bash python -m scripts.seed_data # Or with Docker: docker-compose exec api python scripts/seed_data.py ``` ### Database Migration ```bash # Apply migrations flask db upgrade # With Docker: docker-compose exec api python manage.py db upgrade ``` ### SQLite Browser (Development) ```bash sqlite_web instance/db_file.db --port 9999 --host 0.0.0.0 ``` ## Test Credentials ### OIDC Client | Field | Value | |-------|-------| | client_id | `acme-portal-001` | | client_secret | `acme_secret_portal_2024` | ### Test User | Field | Value | |-------|-------| | email | `bob@acme-corp.com` | | password | `UserPass123!` |