2026-01-08 01:00:26 +10:30
# 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 <repository-url>
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
2026-04-04 16:51:19 +10:30
python -m scripts.seed_data
2026-01-08 01:00:26 +10:30
```
7. **Run the application ** :
``` bash
flask run
2026-04-07 20:03:11 +09:30
# Or in debug mode
FLASK_ENV = development flask run --debug --port 5000
2026-01-08 01:00:26 +10:30
# Or using the WSGI file
python wsgi.py
2026-04-07 20:03:11 +09:30
2026-01-08 01:00:26 +10:30
```
The API will be available at `http://localhost:5000`
2026-04-04 16:51:19 +10:30
## 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
2026-01-08 01:00:26 +10:30
## 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
2026-04-26 18:12:37 +09:30
- `POST /api/v1/auth/sessions/refresh` - Extend session idle window
2026-01-08 01:00:26 +10:30
- `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
2026-02-26 23:18:31 +05:45
2026-04-23 15:41:37 +09:30
### 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.
2026-01-08 01:00:26 +10:30
### Health
- `GET /api/health` - Health check
2026-02-26 23:18:31 +05:45
## O-auth Setup
- Redirect URI
```http://localhost:5000/api/v1/auth/external/[google|microsoft]/callback` ``
2026-01-08 01:00:26 +10:30
## 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
2026-01-08 15:59:53 +10:30
2026-04-26 18:12:37 +09:30
## 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
2026-01-08 15:59:53 +10:30
# Boostrap db
python manage.py db upgrade
2026-04-04 16:51:19 +10:30
## Development Commands
2026-01-09 13:00:02 +10:30
2026-04-04 16:51:19 +10:30
### Run Flask in Development
` ``bash
2026-01-09 13:00:02 +10:30
FLASK_ENV=development flask run --debug --port 8888
2026-04-04 16:51:19 +10:30
` ``
2026-01-09 13:00:02 +10:30
2026-04-04 16:51:19 +10:30
### 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
` ``
2026-01-09 13:00:02 +10:30
2026-04-04 16:51:19 +10:30
## Test Credentials
2026-01-14 18:06:17 +10:30
2026-04-04 16:51:19 +10:30
### OIDC Client
| Field | Value |
|-------|-------|
| client_id | ` acme-portal-001` |
| client_secret | ` acme_secret_portal_2024` |
2026-01-14 18:06:17 +10:30
2026-04-04 16:51:19 +10:30
### Test User
| Field | Value |
|-------|-------|
| email | ` bob@acme -corp.com` |
| password | ` UserPass123!` |