nexgen_mirrors de6f39e7e3 feat(ssh): change SSH key uniqueness to per-user scope
Previously, SSH key fingerprints were globally unique across all users,
preventing the same key from being registered by different users. This
change makes fingerprint uniqueness scoped to individual users.

- Remove global unique constraints on payload and fingerprint columns
- Add composite unique constraint on (user_id, fingerprint)
- Make add_ssh_key operation idempotent for same user
- Return tuple (SSHKey, is_new) from service to indicate creation status
- Update API to return 200 for existing keys, 201 for new keys

BREAKING CHANGE: API behavior changed - duplicate key addition now
returns 200 OK instead of 409 Conflict. Service method signature changed
from returning SSHKey to tuple[SSHKey, bool].
2026-04-25 06:22:08 +09:30
2026-04-21 17:11:03 +09:30
2026-01-08 01:00:26 +10:30
2026-04-07 20:03:11 +09:30
2026-03-22 16:04:29 +05:45
2026-01-08 01:00:26 +10:30
2026-01-14 18:06:26 +10:30
2026-01-08 01:00:26 +10:30
2026-01-15 03:40:29 +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:
git clone <repository-url>
cd authy2/backend
  1. Create virtual environment:
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
  1. Install dependencies:
pip install -r requirements/development.txt
  1. Set up environment variables:
cp .env.example .env
# Edit .env with your configuration
  1. Initialize database:
python scripts/init_db.py
  1. Seed sample data (optional):
python -m scripts.seed_data
  1. Run the application:
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:
docker-compose up -d
  1. Initialize the database (run migrations):
docker-compose exec api python manage.py db upgrade
  1. Seed sample data (optional):
docker-compose exec api python scripts/seed_data.py
  1. Verify health:
curl http://localhost:5000/api/health

Useful Commands

# 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
  • 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:

{
  "version": "1.0",
  "success": true,
  "code": 200,
  "message": "Success message",
  "request_id": "uuid-v4",
  "data": {},
  "meta": {}
}

Error responses:

{
  "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:

flask db migrate -m "Description of changes"

Apply migrations:

flask db upgrade

Rollback:

flask db downgrade

Environment Configuration

  • Development: FLASK_ENV=development
  • Testing: FLASK_ENV=testing
  • Production: FLASK_ENV=production

Production Deployment

Using Gunicorn

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

Boostrap db

python manage.py db upgrade

Development Commands

Run Flask in Development

FLASK_ENV=development flask run --debug --port 8888

Seed Sample Data

python -m scripts.seed_data
# Or with Docker:
docker-compose exec api python scripts/seed_data.py

Database Migration

# Apply migrations
flask db upgrade

# With Docker:
docker-compose exec api python manage.py db upgrade

SQLite Browser (Development)

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!
S
Description
the backend to Gatehouse - A central authentication system thats simple
Readme 1.1 MiB
Languages
Python 99.6%
Shell 0.3%