Skip to content

Htunn/simple-faceid

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

FaceID Authentication Service πŸ”

A production-ready microservice for face-based authentication using FastAPI, PostgreSQL with pgvector, and advanced security features including liveness detection, rate limiting, and comprehensive monitoring.

πŸš€ Features

  • Face Recognition Authentication: 128-dimensional face embeddings using face_recognition library
  • pgvector Integration: Efficient vector similarity search with HNSW indexes
  • Liveness Detection: Passive anti-spoofing to prevent photo/video attacks
  • Rate Limiting: Per-IP and per-endpoint rate limiting with Redis
  • JWT Authentication: Secure token-based authentication
  • Prometheus Metrics: Comprehensive monitoring and observability
  • Structured Logging: JSON logging with correlation IDs
  • Fraud Detection: Track and analyze failed login attempts
  • PostgreSQL + AsyncIO: High-performance async database operations
  • Docker Support: Easy deployment with Docker Compose

οΏ½ Architecture

System Architecture Diagram

flowchart TB
    subgraph Client["Client Layer"]
        WebUI["Web UI<br/>(WebRTC/HTML)"]
        MobileApp["Mobile App"]
        CLI["CLI/Test Script<br/>(capture_test.py)"]
    end

    subgraph API["API Layer (FastAPI)"]
        direction TB
        AuthEndpoints["Auth Endpoints<br/>(/register, /login)"]
        AdminEndpoints["Admin Endpoints<br/>(/failed-attempts)"]
        HealthEndpoints["Health Endpoints<br/>(/health, /ready)"]
        Middleware["Middleware<br/>(CORS, Logging, Metrics)"]
        RateLimiter["Rate Limiter<br/>(slowapi + Redis)"]
    end

    subgraph Services["Business Logic Layer"]
        direction TB
        FaceUtils["Face Recognition<br/>(face_recognition lib)"]
        LivenessDetect["Liveness Detection<br/>(Anti-spoofing)"]
        Security["Security Service<br/>(JWT, Password Hash)"]
        Metrics["Metrics Service<br/>(Prometheus)"]
    end

    subgraph Data["Data Layer"]
        direction LR
        PostgreSQL[("PostgreSQL<br/>+ pgvector<br/>(Face Embeddings)")]
        Redis[("Redis<br/>(Rate Limiting)")]
        Logs[("Logs<br/>(JSON Files)")]
    end

    WebUI --> Middleware
    MobileApp --> Middleware
    CLI --> Middleware
    
    Middleware --> RateLimiter
    RateLimiter --> AuthEndpoints
    RateLimiter --> AdminEndpoints
    Middleware --> HealthEndpoints
    
    AuthEndpoints --> FaceUtils
    AuthEndpoints --> LivenessDetect
    AuthEndpoints --> Security
    AdminEndpoints --> Security
    
    FaceUtils --> PostgreSQL
    LivenessDetect --> PostgreSQL
    Security --> PostgreSQL
    RateLimiter --> Redis
    
    Metrics --> Logs
    Middleware --> Metrics
    
    HealthEndpoints -.->|Check| PostgreSQL
    HealthEndpoints -.->|Check| Redis

    style API fill:#e1f5ff
    style Services fill:#fff4e1
    style Data fill:#ffe1e1
    style Client fill:#e8f5e9
Loading

Authentication Sequence Diagram

sequenceDiagram
    autonumber
    actor User
    participant WebUI as Web UI
    participant API as FastAPI Server
    participant RateLimit as Rate Limiter
    participant Liveness as Liveness Detector
    participant FaceRec as Face Recognition
    participant PgVector as PostgreSQL<br/>+ pgvector
    participant Redis
    participant Metrics as Prometheus

    User->>WebUI: Capture face image
    WebUI->>API: POST /auth/login<br/>(face_image)
    
    API->>RateLimit: Check rate limit
    RateLimit->>Redis: GET request count
    Redis-->>RateLimit: Return count
    
    alt Rate limit exceeded
        RateLimit-->>API: 429 Too Many Requests
        API-->>WebUI: Rate limit error
        API->>Metrics: Record rate_limit_hit
    else Within limit
        RateLimit->>Redis: Increment counter
        
        API->>Liveness: Detect liveness
        Liveness->>Liveness: Analyze texture,<br/>color, brightness
        
        alt Not live (spoofing detected)
            Liveness-->>API: is_live=false, score
            API->>PgVector: Record failed attempt
            API-->>WebUI: 401 Unauthorized<br/>(Liveness failed)
            API->>Metrics: Record liveness_check_failed
        else Live face detected
            Liveness-->>API: is_live=true, score
            API->>Metrics: Record liveness_check_success
            
            API->>FaceRec: Extract face embedding
            FaceRec-->>API: 128-dim vector
            
            API->>PgVector: Vector similarity search<br/>(HNSW index, cosine distance)
            Note over PgVector: SELECT * FROM users<br/>WHERE is_active = true<br/>ORDER BY face_embedding <=> ?<br/>LIMIT 1
            PgVector-->>API: Best match + distance
            
            alt Match found (distance < threshold)
                API->>API: Generate JWT tokens
                API->>Metrics: Record login_success
                API-->>WebUI: 200 OK<br/>{access_token, user, confidence}
                WebUI-->>User: Login successful
            else No match / below threshold
                API->>PgVector: Record failed attempt<br/>(reason: no_match)
                API->>Metrics: Record login_failed
                API-->>WebUI: 401 Unauthorized<br/>(Face not recognized)
            end
        end
    end
Loading

Registration Flow Diagram

flowchart TD
    Start([User Starts Registration]) --> Capture[Capture Face Image]
    Capture --> Submit[Submit Form:<br/>username, email,<br/>password, face_image]
    
    Submit --> RateCheck{Rate Limit<br/>Check}
    RateCheck -->|Exceeded| RateError[Return 429<br/>Too Many Requests]
    RateError --> End([End])
    
    RateCheck -->|OK| ValidateInput{Validate Input}
    ValidateInput -->|Invalid| ValidationError[Return 422<br/>Validation Error]
    ValidationError --> End
    
    ValidateInput -->|Valid| CheckExists{User Exists?}
    CheckExists -->|Yes| ExistsError[Return 400<br/>User Already Exists]
    ExistsError --> End
    
    CheckExists -->|No| LivenessCheck[Liveness Detection]
    LivenessCheck --> LivenessDecision{Is Live?}
    
    LivenessDecision -->|No| LivenessError[Return 401<br/>Spoofing Detected]
    LivenessError --> RecordAttempt1[Record Failed Attempt]
    RecordAttempt1 --> End
    
    LivenessDecision -->|Yes| ExtractFace[Extract Face<br/>from Image]
    ExtractFace --> FaceFound{Face Found?}
    
    FaceFound -->|No| NoFaceError[Return 400<br/>No Face Detected]
    NoFaceError --> End
    
    FaceFound -->|Yes| QualityCheck{Image Quality<br/>Check}
    QualityCheck -->|Poor| QualityError[Return 400<br/>Poor Image Quality]
    QualityError --> End
    
    QualityCheck -->|Good| ExtractEmbedding[Extract 128-dim<br/>Face Embedding]
    ExtractEmbedding --> HashPassword[Hash Password<br/>with bcrypt]
    
    HashPassword --> CreateUser[Create User Record<br/>in PostgreSQL]
    CreateUser --> StoreEmbedding[Store Face Embedding<br/>as Vector in pgvector]
    StoreEmbedding --> CreateIndex[Create/Update<br/>HNSW Index]
    
    CreateIndex --> GenerateTokens[Generate JWT<br/>Access & Refresh Tokens]
    GenerateTokens --> RecordMetrics[Record Success Metrics]
    RecordMetrics --> Success[Return 201<br/>Registration Successful]
    Success --> End
    
    style Start fill:#e8f5e9
    style End fill:#ffebee
    style Success fill:#c8e6c9
    style RateError fill:#ffcdd2
    style ValidationError fill:#ffcdd2
    style ExistsError fill:#ffcdd2
    style LivenessError fill:#ffcdd2
    style NoFaceError fill:#ffcdd2
    style QualityError fill:#ffcdd2
    style LivenessCheck fill:#fff9c4
    style ExtractEmbedding fill:#b3e5fc
    style StoreEmbedding fill:#b3e5fc
Loading

Component Architecture Diagram

graph TB
    subgraph "FastAPI Application"
        Main[main.py<br/>App Initialization]
        
        subgraph "Configuration"
            Config[config.py<br/>Settings Management]
            Env[.env<br/>Environment Variables]
        end
        
        subgraph "Routes"
            AuthRoutes[auth.py<br/>Registration & Login]
            AdminRoutes[admin.py<br/>Fraud Detection]
            HealthRoutes[health.py<br/>Health Checks]
        end
        
        subgraph "Middleware"
            LogMiddleware[logging.py<br/>Request Logging]
            MetricsMiddleware[metrics.py<br/>HTTP Metrics]
            CORSMiddleware[CORS<br/>Cross-Origin]
        end
        
        subgraph "Services"
            FaceService[face_utils.py<br/>Face Recognition]
            LivenessService[liveness.py<br/>Anti-spoofing]
            SecurityService[security.py<br/>JWT & Passwords]
            MetricsService[metrics.py<br/>Prometheus]
        end
        
        subgraph "Data Access"
            Database[database.py<br/>SQLAlchemy Async]
            Models[models.py<br/>User & Attempt Models]
            Schemas[schemas.py<br/>Pydantic Validation]
        end
        
        subgraph "Dependencies"
            Deps[dependencies.py<br/>DI Container]
        end
    end
    
    subgraph "External Services"
        PG[(PostgreSQL<br/>+ pgvector)]
        RedisDB[(Redis)]
        PrometheusDB[(Prometheus)]
    end
    
    subgraph "Infrastructure"
        Alembic[Alembic<br/>Migrations]
        Docker[Docker Compose]
        Logs[JSON Logs]
    end
    
    Main --> Config
    Main --> AuthRoutes
    Main --> AdminRoutes
    Main --> HealthRoutes
    Main --> LogMiddleware
    Main --> MetricsMiddleware
    Main --> CORSMiddleware
    
    Config --> Env
    
    AuthRoutes --> Deps
    AdminRoutes --> Deps
    Deps --> FaceService
    Deps --> LivenessService
    Deps --> SecurityService
    Deps --> Database
    
    AuthRoutes --> MetricsService
    AdminRoutes --> MetricsService
    
    FaceService --> Models
    LivenessService --> Models
    SecurityService --> Models
    
    Database --> Models
    Database --> Schemas
    Database --> PG
    
    MetricsService --> PrometheusDB
    LogMiddleware --> Logs
    
    AuthRoutes --> RedisDB
    
    Alembic --> PG
    Docker --> PG
    Docker --> RedisDB
    
    style Main fill:#4fc3f7
    style Config fill:#fff59d
    style Database fill:#ef5350
    style MetricsService fill:#66bb6a
    style FaceService fill:#ab47bc
    style LivenessService fill:#ab47bc
Loading

Database Schema & pgvector Integration

erDiagram
    users ||--o{ failed_login_attempts : has
    
    users {
        uuid id PK
        string username UK
        string email UK
        string password_hash
        vector_128 face_embedding "pgvector Vector(128)"
        string model_version "face_recognition version"
        boolean is_active
        boolean is_locked
        timestamp locked_until
        timestamp created_at
        timestamp updated_at
    }
    
    failed_login_attempts {
        uuid id PK
        uuid user_id FK
        string ip_address
        string user_agent
        string reason "no_match|liveness_failed|rate_limit"
        float confidence_score
        float liveness_score
        timestamp attempted_at
    }
Loading

pgvector HNSW Index:

CREATE INDEX face_embedding_hnsw_idx ON users 
USING hnsw (face_embedding vector_cosine_ops);

Vector Similarity Search:

SELECT * FROM users 
WHERE is_active = true 
  AND NOT is_locked
ORDER BY face_embedding <=> '[0.1, 0.2, ...]'::vector
LIMIT 1;

οΏ½πŸ“‹ Requirements

  • Python 3.12+
  • PostgreSQL 16+ with pgvector extension
  • Redis 7+
  • Docker & Docker Compose (optional)

πŸ› οΈ Installation

1. Clone and Setup Environment

# Clone repository
cd simple-faceid

# Create and activate virtual environment
python3.12 -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt

2. Configure Environment

# Copy example environment file
cp .env.example .env

# Edit .env and set required values:
# - SECRET_KEY: Generate a secure random string (min 32 chars)
# - DATABASE_URL: PostgreSQL connection string
# - REDIS_URL: Redis connection string

Generate a secure secret key:

python -c "import secrets; print(secrets.token_urlsafe(32))"

3. Setup Database

# Install PostgreSQL with pgvector
# On macOS:
brew install postgresql@16 pgvector

# On Ubuntu:
sudo apt-get install postgresql-16 postgresql-16-pgvector

# Create database
createdb faceid_db

# Run migrations
alembic upgrade head

4. Start Redis

# On macOS:
brew services start redis

# On Ubuntu:
sudo systemctl start redis

# Or use Docker:
docker run -d -p 6379:6379 redis:7-alpine

🐳 Docker Deployment

The easiest way to run the service:

# Build and start all services
docker-compose up --build

# Run in background
docker-compose up -d

# View logs
docker-compose logs -f app

# Stop services
docker-compose down

Services will be available at:

🚦 Running the Service

Development Mode

# With auto-reload
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

# Or using Python directly
python -m app.main

Production Mode

# Update .env:
ENVIRONMENT=production
DEBUG=false
RELOAD=false
WORKERS=4

# Run with Gunicorn
gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000

πŸ“– API Documentation

Once running, visit:

Key Endpoints

Authentication

Register User

POST /api/v1/auth/register
Content-Type: multipart/form-data

Fields:
- username: string
- email: string
- password: string
- face_image: file (JPEG/PNG)

Login with Face

POST /api/v1/auth/login
Content-Type: multipart/form-data

Fields:
- face_image: file (JPEG/PNG)

Returns:
- access_token: JWT token
- user: User object
- liveness_score: float
- confidence_score: float

Admin (Requires Authentication)

GET /api/v1/admin/failed-attempts?hours=24
GET /api/v1/admin/suspicious-activity?threshold=5
GET /api/v1/admin/metrics-summary

Health Checks

GET /health          # Basic health check
GET /ready           # Readiness check (DB, Redis, pgvector)
GET /metrics         # Prometheus metrics

πŸ§ͺ Testing with Webcam

Web Interface

  1. Start the service
  2. Open static/index.html in your browser
  3. Allow camera access
  4. Capture your face image
  5. Submit for registration or login

Python Script

# Install OpenCV
pip install opencv-python requests

# Run capture script
python capture_test.py

πŸ“Š Monitoring & Metrics

Prometheus Metrics

Access metrics at http://localhost:8000/metrics

Key Metrics:

  • faceid_registration_attempts_total - Registration attempts by status
  • faceid_login_attempts_total - Login attempts by status/reason
  • faceid_liveness_checks_total - Liveness detection results
  • faceid_face_match_latency_seconds - Face matching performance
  • faceid_vector_search_duration_seconds - Vector search performance
  • faceid_rate_limit_hits_total - Rate limit violations
  • faceid_active_users_total - Active user count
  • faceid_locked_accounts_total - Locked account count

Logs

Structured JSON logs in logs/app.log:

{
  "timestamp": "2026-02-01 12:00:00",
  "level": "INFO",
  "logger": "app.routes.auth",
  "message": "User logged in successfully",
  "correlation_id": "abc-123-def",
  "user_id": "user-uuid",
  "environment": "production"
}

πŸ”’ Security Features

Rate Limiting

  • Registration: 5 requests/hour per IP
  • Login: 10 requests/minute per IP
  • Default: 100 requests/hour per IP

Fraud Detection

  • Track failed login attempts by IP and user
  • Automatic account locking after 10 failed attempts in 1 hour
  • Lock duration: 30 minutes (configurable)
  • Failed attempt retention: 30 days

Liveness Detection

  • Passive detection (single image)
  • Texture analysis and quality checks
  • Configurable confidence threshold (default: 0.7)
  • Can be extended with ML models (ONNX)

Face Recognition

  • 128-dimensional embeddings
  • Cosine distance similarity
  • Configurable tolerance (default: 0.6)
  • HNSW index for fast vector search
  • Metadata pre-filtering for scalability

πŸ”§ Configuration

All configuration via environment variables. See .env.example for full list.

Key Settings:

# Face Recognition
FACE_RECOGNITION_TOLERANCE=0.6      # Lower = stricter matching
FACE_DETECTION_MODEL=hog            # hog (fast) or cnn (accurate)

# Liveness Detection
LIVENESS_ENABLED=true
LIVENESS_THRESHOLD=0.7              # Higher = stricter

# Rate Limiting
RATE_LIMIT_REGISTER=5/hour
RATE_LIMIT_LOGIN=10/minute

# Security
ACCESS_TOKEN_EXPIRE_MINUTES=30
MAX_FAILED_LOGIN_ATTEMPTS=10

πŸ“ Project Structure

simple-faceid/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ main.py                 # FastAPI application
β”‚   β”œβ”€β”€ config.py               # Pydantic settings
β”‚   β”œβ”€β”€ database.py             # Database setup
β”‚   β”œβ”€β”€ models.py               # SQLAlchemy models
β”‚   β”œβ”€β”€ schemas.py              # Pydantic schemas
β”‚   β”œβ”€β”€ security.py             # JWT & password hashing
β”‚   β”œβ”€β”€ dependencies.py         # FastAPI dependencies
β”‚   β”œβ”€β”€ face_utils.py           # Face recognition logic
β”‚   β”œβ”€β”€ liveness.py             # Liveness detection
β”‚   β”œβ”€β”€ logging_config.py       # Structured logging
β”‚   β”œβ”€β”€ metrics.py              # Prometheus metrics
β”‚   β”œβ”€β”€ middleware/
β”‚   β”‚   β”œβ”€β”€ logging.py          # Request logging
β”‚   β”‚   └── metrics.py          # Metrics collection
β”‚   └── routes/
β”‚       β”œβ”€β”€ auth.py             # Authentication endpoints
β”‚       β”œβ”€β”€ admin.py            # Admin endpoints
β”‚       └── health.py           # Health checks
β”œβ”€β”€ alembic/
β”‚   β”œβ”€β”€ versions/
β”‚   β”‚   └── 001_initial.py      # Initial migration
β”‚   └── env.py                  # Alembic config
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ conftest.py             # Pytest fixtures
β”‚   └── test_auth.py            # Auth tests
β”œβ”€β”€ static/
β”‚   └── index.html              # WebRTC test page
β”œβ”€β”€ docker/
β”‚   └── postgres-init.sh        # PostgreSQL init script
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ .env.example
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ Dockerfile
└── README.md

πŸ§ͺ Running Tests

# Install test dependencies
pip install pytest pytest-asyncio pytest-cov httpx

# Run tests
pytest

# With coverage
pytest --cov=app --cov-report=html

# Run specific test
pytest tests/test_auth.py -v

πŸš€ Performance Optimization

Vector Search Optimization

  1. HNSW Index: Already configured for fast similarity search
  2. Pre-filtering: Enabled by default (filter by is_active before vector search)
  3. Limit Results: Only fetch top 5 candidates (configurable)

Database Tuning

-- Monitor query performance
EXPLAIN ANALYZE 
SELECT * FROM users 
ORDER BY face_embedding <=> '[...]' 
LIMIT 5;

-- Adjust HNSW parameters for your data size
CREATE INDEX idx_users_face_embedding_hnsw 
ON users USING hnsw (face_embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

Scaling Considerations

  • < 10K users: Current setup works great
  • 10K - 100K users: Increase DB connection pool, add Redis cluster
  • 100K - 1M users: Consider read replicas, cache frequently accessed embeddings
  • > 1M users: Shard by user cohorts, implement caching layer

πŸ› Troubleshooting

Common Issues

pgvector extension not found:

# Install pgvector for your PostgreSQL version
# Then in psql:
CREATE EXTENSION vector;

Face recognition installation issues:

# Install system dependencies first
# macOS:
brew install cmake

# Ubuntu:
sudo apt-get install cmake build-essential

# Then reinstall
pip install --upgrade --force-reinstall face-recognition

Redis connection error:

# Check Redis is running
redis-cli ping  # Should return "PONG"

# Or start Redis
brew services start redis  # macOS
sudo systemctl start redis  # Linux

πŸ“ License

MIT License - see LICENSE file for details

🀝 Contributing

Contributions welcome! Please read CONTRIBUTING.md for guidelines.

πŸ“§ Support

For issues and questions:


Built with ❀️ using FastAPI, PostgreSQL, and pgvector

About

A production-ready microservice for face-based authentication using FastAPI, PostgreSQL with pgvector, and advanced security features including liveness detection, rate limiting, and comprehensive monitoring.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors