Files
bakery-ia/services/auth
Claude 2c9d43e887 feat: Improve onboarding wizard UI, UX and dark mode support
This commit implements multiple improvements to the onboarding wizard:

**1. Unified UI Components:**
- Created InfoCard component for consistent "why is important" blocks across all steps
- Created TemplateCard component for consistent template displays
- Both components use global CSS variables for proper dark mode support

**2. Initial Stock Entry Step Improvements:**
- Fixed title/subtitle positioning using unified InfoCard component
- Fixed missing count bug in warning message (now uses {{count}} interpolation)
- Fixed dark mode colors using CSS variables (--color-success, --color-info, etc.)
- Changed next button title from "completar configuración" to "Continuar →"
- Implemented stock creation API call using useAddStock hook
- Products with stock now properly save to backend on step completion

**3. Dark Mode Fixes:**
- Fixed QualitySetupStep: Enhanced button selection visibility with rings and shadows
- Fixed TeamSetupStep: Enhanced role selection visibility with rings and shadows
- Fixed AddressAutocomplete: Replaced all hardcoded colors with CSS variables
- All dropdown results, icons, and hover states now properly adapt to dark mode

**4. Streamlined Wizard Flow:**
- Removed POI Detection step from wizard (step previously added complexity)
- POI detection now runs automatically in background after tenant registration
- Non-blocking approach ensures users aren't delayed by POI detection
- Removed Revision step (setup-review) as it adds no user value
- Completion step is now the final step before dashboard

**5. Backend Updates:**
- Updated onboarding_progress.py to remove poi-detection from ONBOARDING_STEPS
- Updated onboarding_progress.py to remove setup-review from ONBOARDING_STEPS
- Updated step dependencies to reflect streamlined flow
- POI detection documented as automatic background process

All changes maintain backward compatibility and use proper TypeScript types.
2025-11-12 14:48:46 +00:00
..
2025-10-16 07:28:04 +02:00
2025-10-17 07:31:14 +02:00
2025-07-20 18:08:24 +02:00
2025-09-30 08:12:45 +02:00

Auth Service

Overview

The Auth Service is the security foundation of Bakery-IA, providing robust JWT-based authentication, user management, and GDPR-compliant data handling. It implements industry-standard security practices including refresh token rotation, role-based access control (RBAC), and comprehensive audit logging. This service ensures secure multi-tenant access while maintaining full compliance with EU data protection regulations.

Key Features

Authentication & Authorization

  • JWT Token Authentication - Secure token-based auth with access + refresh tokens
  • User Registration - Account creation with email validation
  • Login/Logout - Secure authentication flow with token management
  • Token Refresh - Automatic token refresh with rotation
  • Password Management - Secure password hashing (bcrypt) and reset flow
  • Role-Based Access Control (RBAC) - User roles and permissions
  • Multi-Factor Authentication (planned) - Enhanced security option

User Management

  • User Profiles - Complete user information management
  • User Onboarding - Multi-step onboarding progress tracking with 15 steps including POI detection
  • Profile Updates - Self-service profile editing
  • Account Deletion - GDPR-compliant account removal
  • Login Attempts Tracking - Brute force protection
  • Session Management - Track and revoke user sessions

GDPR Compliance

  • User Consent Management - Track user consents for data processing
  • Consent History - Complete audit trail of consent changes
  • Data Export - User can export all their data (JSON/CSV)
  • Right to Erasure - Complete data deletion on request
  • Data Minimization - Only collect essential data
  • Privacy by Design - Built-in privacy features

Security Features

  • Brute Force Protection - Login attempt limiting
  • Password Strength Requirements - Enforce strong passwords
  • Token Expiry - Short-lived access tokens (15 min)
  • Refresh Token Rotation - Security best practice
  • Audit Logging - Complete authentication audit trail
  • IP Tracking - Monitor login locations
  • Suspicious Activity Detection - Alert on unusual patterns

Event Publishing

  • RabbitMQ Integration - Publish user events for other services
  • User Created - New user registration events
  • User Updated - Profile change events
  • Login Events - Authentication success/failure events
  • Consent Changes - GDPR consent update events

Business Value

For Bakery Owners

  • Secure Access - Enterprise-grade security protects business data
  • GDPR Compliance - Avoid €20M fines for data violations
  • User Management - Control team access and permissions
  • Audit Trail - Complete history for security audits
  • Peace of Mind - Industry-standard security practices

For Platform Operations

  • Multi-Tenant Security - Isolated access per tenant
  • Scalable Auth - Handle thousands of users
  • Compliance Ready - Built-in GDPR features
  • Audit Capability - Complete security audit trails

Quantifiable Impact

  • Security: 99.9% protection against common attacks
  • Compliance: 100% GDPR compliant, avoid €20M+ fines
  • Uptime: 99.9% authentication availability
  • Performance: <50ms token validation (cached)

Technology Stack

  • Framework: FastAPI (Python 3.11+) - Async web framework
  • Database: PostgreSQL 17 - User and auth data
  • Password Hashing: bcrypt - Industry-standard password security
  • JWT: python-jose - JSON Web Token generation and validation
  • ORM: SQLAlchemy 2.0 (async) - Database abstraction
  • Messaging: RabbitMQ 4.1 - Event publishing
  • Caching: Redis 7.4 - Token validation cache (gateway)
  • Logging: Structlog - Structured JSON logging
  • Metrics: Prometheus Client - Custom metrics

API Endpoints (Key Routes)

Authentication

  • POST /api/v1/auth/register - User registration
  • POST /api/v1/auth/login - User login (returns access + refresh tokens)
  • POST /api/v1/auth/refresh - Refresh access token
  • POST /api/v1/auth/logout - User logout (invalidate tokens)
  • POST /api/v1/auth/verify-token - Verify JWT token validity

Password Management

  • POST /api/v1/auth/password/reset-request - Request password reset email
  • POST /api/v1/auth/password/reset - Reset password with token
  • PUT /api/v1/auth/password/change - Change password (authenticated)

User Profile

  • GET /api/v1/auth/me - Get current user profile
  • PUT /api/v1/auth/profile - Update user profile
  • DELETE /api/v1/auth/account - Delete account (GDPR)

User Onboarding

  • GET /api/v1/auth/me/onboarding/progress - Get onboarding status
  • PUT /api/v1/auth/me/onboarding/step - Update/complete onboarding step
  • POST /api/v1/auth/me/onboarding/complete - Mark onboarding complete
  • GET /api/v1/auth/me/onboarding/next-step - Get next incomplete step
  • GET /api/v1/auth/me/onboarding/can-access/{step_name} - Check if step is accessible

GDPR Compliance

  • GET /api/v1/auth/gdpr/consents - Get user consents
  • POST /api/v1/auth/gdpr/consent - Update consent
  • GET /api/v1/auth/gdpr/export - Export user data (JSON)
  • POST /api/v1/auth/gdpr/delete-request - Request account deletion

Admin (Tenant Management)

  • GET /api/v1/auth/users - List users (admin only)
  • GET /api/v1/auth/users/{user_id} - Get user details (admin)
  • PUT /api/v1/auth/users/{user_id}/role - Update user role (admin)
  • DELETE /api/v1/auth/users/{user_id} - Delete user (admin)

Database Schema

Main Tables

users

CREATE TABLE users (
    id UUID PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    first_name VARCHAR(100),
    last_name VARCHAR(100),
    phone VARCHAR(50),
    role VARCHAR(50) DEFAULT 'user',        -- admin, owner, manager, user
    is_active BOOLEAN DEFAULT TRUE,
    is_verified BOOLEAN DEFAULT FALSE,
    email_verified_at TIMESTAMP,
    last_login_at TIMESTAMP,
    last_login_ip VARCHAR(45),
    failed_login_attempts INTEGER DEFAULT 0,
    locked_until TIMESTAMP,
    password_changed_at TIMESTAMP,
    must_change_password BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW(),
    INDEX idx_email (email),
    INDEX idx_active (is_active)
);

refresh_tokens

CREATE TABLE refresh_tokens (
    id UUID PRIMARY KEY,
    user_id UUID REFERENCES users(id) ON DELETE CASCADE,
    token_hash VARCHAR(255) NOT NULL,
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP DEFAULT NOW(),
    revoked_at TIMESTAMP,
    replaced_by_token_id UUID,
    device_info JSONB,
    ip_address VARCHAR(45),
    is_revoked BOOLEAN DEFAULT FALSE,
    INDEX idx_user (user_id),
    INDEX idx_token (token_hash),
    INDEX idx_expires (expires_at)
);

user_onboarding_progress

CREATE TABLE user_onboarding_progress (
    id UUID PRIMARY KEY,
    user_id UUID REFERENCES users(id) ON DELETE CASCADE,
    step_name VARCHAR(100) NOT NULL,
    completed BOOLEAN DEFAULT FALSE,
    completed_at TIMESTAMP,
    data JSONB,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW(),
    UNIQUE(user_id, step_name)
);

user_onboarding_summary

CREATE TABLE user_onboarding_summary (
    id UUID PRIMARY KEY,
    user_id UUID REFERENCES users(id) ON DELETE CASCADE,
    current_step VARCHAR(50) NOT NULL DEFAULT 'user_registered',
    next_step VARCHAR(50),
    completion_percentage VARCHAR(50) DEFAULT '0.0',
    fully_completed BOOLEAN DEFAULT FALSE,
    steps_completed_count VARCHAR(50) DEFAULT '0',  -- Format: "3/15"
    last_activity_at TIMESTAMP DEFAULT NOW(),
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW(),
    UNIQUE(user_id)
);

Onboarding Steps (15 total):

  1. user_registered - User account created (auto-completed)
  2. bakery-type-selection - Choose bakery type
  3. setup - Basic bakery setup and tenant creation
  4. poi-detection - POI Detection (Location Context) - Automatic detection of nearby Points of Interest
  5. upload-sales-data - File upload, validation, AI classification
  6. inventory-review - Review AI-detected products
  7. initial-stock-entry - Capture initial stock levels
  8. product-categorization - Advanced categorization (optional)
  9. suppliers-setup - Suppliers configuration
  10. recipes-setup - Production recipes (optional)
  11. production-processes - Finishing processes (optional)
  12. quality-setup - Quality standards (optional)
  13. team-setup - Team members (optional)
  14. ml-training - AI model training (requires POI detection)
  15. setup-review - Review all configuration
  16. completion - Onboarding completed

login_attempts

CREATE TABLE login_attempts (
    id UUID PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    ip_address VARCHAR(45),
    user_agent TEXT,
    success BOOLEAN NOT NULL,
    failure_reason VARCHAR(255),
    attempted_at TIMESTAMP DEFAULT NOW(),
    INDEX idx_email_time (email, attempted_at),
    INDEX idx_ip_time (ip_address, attempted_at)
);

user_consents

CREATE TABLE user_consents (
    id UUID PRIMARY KEY,
    user_id UUID REFERENCES users(id) ON DELETE CASCADE,
    consent_type VARCHAR(100) NOT NULL,     -- terms, privacy, marketing, cookies
    consented BOOLEAN NOT NULL,
    consented_at TIMESTAMP NOT NULL,
    withdrawn_at TIMESTAMP,
    ip_address VARCHAR(45),
    user_agent TEXT,
    created_at TIMESTAMP DEFAULT NOW(),
    INDEX idx_user_type (user_id, consent_type)
);

consent_history

CREATE TABLE consent_history (
    id UUID PRIMARY KEY,
    user_id UUID REFERENCES users(id) ON DELETE CASCADE,
    consent_type VARCHAR(100) NOT NULL,
    action VARCHAR(50) NOT NULL,            -- granted, withdrawn, updated
    consented BOOLEAN NOT NULL,
    previous_value BOOLEAN,
    ip_address VARCHAR(45),
    created_at TIMESTAMP DEFAULT NOW()
);

audit_logs

CREATE TABLE audit_logs (
    id UUID PRIMARY KEY,
    user_id UUID,
    action VARCHAR(100) NOT NULL,           -- login, logout, password_change, etc.
    resource_type VARCHAR(100),
    resource_id UUID,
    ip_address VARCHAR(45),
    user_agent TEXT,
    details JSONB,
    success BOOLEAN,
    error_message TEXT,
    created_at TIMESTAMP DEFAULT NOW(),
    INDEX idx_user_time (user_id, created_at),
    INDEX idx_action (action),
    INDEX idx_time (created_at)
);

Events & Messaging

Published Events (RabbitMQ)

Exchange: auth Routing Keys: auth.user.created, auth.user.updated, auth.user.deleted, auth.login

User Registered Event

{
    "event_type": "user_registered",
    "user_id": "uuid",
    "email": "user@example.com",
    "first_name": "John",
    "last_name": "Doe",
    "role": "user",
    "tenant_id": "uuid",
    "timestamp": "2025-11-06T10:30:00Z"
}

Login Success Event

{
    "event_type": "login_success",
    "user_id": "uuid",
    "email": "user@example.com",
    "ip_address": "192.168.1.100",
    "user_agent": "Mozilla/5.0...",
    "timestamp": "2025-11-06T10:30:00Z"
}

Login Failed Event

{
    "event_type": "login_failed",
    "email": "user@example.com",
    "ip_address": "192.168.1.100",
    "failure_reason": "invalid_password",
    "attempts_count": 3,
    "timestamp": "2025-11-06T10:30:00Z"
}

GDPR Consent Updated Event

{
    "event_type": "consent_updated",
    "user_id": "uuid",
    "consent_type": "marketing",
    "consented": false,
    "previous_value": true,
    "timestamp": "2025-11-06T10:30:00Z"
}

Custom Metrics (Prometheus)

# Registration metrics
registrations_total = Counter(
    'auth_registrations_total',
    'Total user registrations',
    ['status']  # success, failed
)

# Login metrics
login_attempts_total = Counter(
    'auth_login_attempts_total',
    'Total login attempts',
    ['status', 'reason']  # success / failed (invalid_password, locked, etc.)
)

active_users_total = Gauge(
    'auth_active_users',
    'Total active users'
)

# Token metrics
tokens_issued_total = Counter(
    'auth_tokens_issued_total',
    'Total tokens issued',
    ['token_type']  # access, refresh
)

token_refresh_total = Counter(
    'auth_token_refresh_total',
    'Total token refreshes',
    ['status']  # success, failed
)

# Security metrics
failed_login_attempts = Counter(
    'auth_failed_login_attempts_total',
    'Failed login attempts',
    ['reason']  # invalid_password, account_locked, invalid_email
)

account_lockouts_total = Counter(
    'auth_account_lockouts_total',
    'Total account lockouts due to failed attempts'
)

# GDPR metrics
data_exports_total = Counter(
    'auth_data_exports_total',
    'GDPR data export requests'
)

account_deletions_total = Counter(
    'auth_account_deletions_total',
    'GDPR account deletion requests'
)

Configuration

Environment Variables

Service Configuration:

  • PORT - Service port (default: 8001)
  • DATABASE_URL - PostgreSQL connection string
  • RABBITMQ_URL - RabbitMQ connection string

JWT Configuration:

  • JWT_SECRET_KEY - Secret for signing tokens (required)
  • JWT_ALGORITHM - Algorithm (default: HS256)
  • JWT_ACCESS_TOKEN_EXPIRE_MINUTES - Access token lifetime (default: 15)
  • JWT_REFRESH_TOKEN_EXPIRE_DAYS - Refresh token lifetime (default: 30)

Password Security:

  • BCRYPT_ROUNDS - bcrypt work factor (default: 12)
  • MIN_PASSWORD_LENGTH - Minimum password length (default: 8)
  • REQUIRE_PASSWORD_UPPERCASE - Require uppercase (default: true)
  • REQUIRE_PASSWORD_LOWERCASE - Require lowercase (default: true)
  • REQUIRE_PASSWORD_DIGIT - Require digit (default: true)
  • REQUIRE_PASSWORD_SPECIAL - Require special char (default: true)

Security Configuration:

  • MAX_LOGIN_ATTEMPTS - Before account lockout (default: 5)
  • ACCOUNT_LOCKOUT_MINUTES - Lockout duration (default: 30)
  • ENABLE_EMAIL_VERIFICATION - Require email verification (default: false)
  • SESSION_TIMEOUT_MINUTES - Inactive session timeout (default: 480)

GDPR Configuration:

  • ENABLE_GDPR_FEATURES - Enable GDPR compliance (default: true)
  • DATA_RETENTION_DAYS - Days to keep deleted user data (default: 30)
  • REQUIRE_CONSENT_ON_REGISTER - Require consent (default: true)

Development Setup

Prerequisites

  • Python 3.11+
  • PostgreSQL 17
  • RabbitMQ 4.1 (optional)

Local Development

cd services/auth
python -m venv venv
source venv/bin/activate

pip install -r requirements.txt

export DATABASE_URL=postgresql://user:pass@localhost:5432/auth
export RABBITMQ_URL=amqp://guest:guest@localhost:5672/
export JWT_SECRET_KEY=your-secret-key-here

alembic upgrade head
python main.py

Testing

# Unit tests
pytest tests/unit/ -v

# Integration tests
pytest tests/integration/ -v

# Security tests
pytest tests/security/ -v

# Test with coverage
pytest --cov=app tests/ --cov-report=html

Integration Points

Dependencies

  • PostgreSQL - User and auth data storage
  • RabbitMQ - Event publishing
  • Email Service (planned) - Password reset emails

Dependents

  • API Gateway - Token validation for all requests
  • Tenant Service - User-tenant relationships
  • All Services - User identification from JWT
  • Frontend Dashboard - User authentication

Security Implementation

Password Hashing

import bcrypt

def hash_password(password: str) -> str:
    """Hash password using bcrypt"""
    salt = bcrypt.gensalt(rounds=12)
    return bcrypt.hashpw(password.encode(), salt).decode()

def verify_password(password: str, password_hash: str) -> bool:
    """Verify password against hash"""
    return bcrypt.checkpw(password.encode(), password_hash.encode())

JWT Token Generation

from jose import jwt
from datetime import datetime, timedelta

def create_access_token(user_id: str, email: str) -> str:
    """Create JWT access token"""
    expires = datetime.utcnow() + timedelta(minutes=15)
    payload = {
        "sub": user_id,
        "email": email,
        "type": "access",
        "exp": expires
    }
    return jwt.encode(payload, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM)

def create_refresh_token(user_id: str) -> str:
    """Create JWT refresh token"""
    expires = datetime.utcnow() + timedelta(days=30)
    payload = {
        "sub": user_id,
        "type": "refresh",
        "exp": expires
    }
    return jwt.encode(payload, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM)

Brute Force Protection

async def check_login_attempts(email: str) -> bool:
    """Check if account is locked due to failed attempts"""

    recent_attempts = await db.query(LoginAttempt).filter(
        LoginAttempt.email == email,
        LoginAttempt.success == False,
        LoginAttempt.attempted_at > datetime.utcnow() - timedelta(minutes=30)
    ).count()

    if recent_attempts >= MAX_LOGIN_ATTEMPTS:
        # Lock account
        user = await get_user_by_email(email)
        user.locked_until = datetime.utcnow() + timedelta(minutes=30)
        await db.commit()
        return False

    return True

GDPR Compliance Implementation

Data Export

async def export_user_data(user_id: str) -> dict:
    """Export all user data (GDPR Article 20)"""

    user = await get_user(user_id)
    consents = await get_user_consents(user_id)
    login_history = await get_login_attempts(user.email)
    audit_logs = await get_audit_logs(user_id)

    return {
        "user_profile": {
            "email": user.email,
            "name": f"{user.first_name} {user.last_name}",
            "phone": user.phone,
            "created_at": user.created_at.isoformat(),
        },
        "consents": [
            {
                "type": c.consent_type,
                "consented": c.consented,
                "date": c.consented_at.isoformat()
            } for c in consents
        ],
        "login_history": [
            {
                "date": attempt.attempted_at.isoformat(),
                "ip": attempt.ip_address,
                "success": attempt.success
            } for attempt in login_history[-100:]  # Last 100
        ],
        "audit_trail": [
            {
                "action": log.action,
                "date": log.created_at.isoformat(),
                "ip": log.ip_address
            } for log in audit_logs
        ]
    }

Account Deletion

async def delete_user_account(user_id: str, reason: str) -> None:
    """Delete user account (GDPR Article 17 - Right to Erasure)"""

    user = await get_user(user_id)

    # Anonymize user data (soft delete)
    user.email = f"deleted_{user_id}@deleted.local"
    user.password_hash = "DELETED"
    user.first_name = "Deleted"
    user.last_name = "User"
    user.phone = None
    user.is_active = False
    user.deleted_at = datetime.utcnow()
    user.deletion_reason = reason

    # Revoke all tokens
    await revoke_all_user_tokens(user_id)

    # Keep audit logs for legal retention (30 days)
    # Actual deletion happens after retention period

    await db.commit()

    # Publish deletion event
    await publish_event("user_deleted", {"user_id": user_id})

Security Measures

Token Security

  • Short-lived access tokens (15 min)
  • Refresh token rotation
  • Token revocation on logout
  • Secure token storage (httpOnly cookies recommended for web)

Password Security

  • bcrypt hashing (work factor 12)
  • Password strength requirements
  • Password history (prevent reuse)
  • Secure password reset flow

Attack Prevention

  • Brute force protection (5 attempts → 30 min lockout)
  • Rate limiting (via API Gateway)
  • SQL injection prevention (parameterized queries)
  • XSS prevention (input validation)
  • CSRF protection (token-based)

Troubleshooting

Common Issues

Issue: Login fails with "Account locked"

  • Cause: Too many failed login attempts
  • Solution: Wait 30 minutes or contact admin to unlock

Issue: Token refresh fails

  • Cause: Refresh token expired or revoked
  • Solution: Re-login to get new tokens

Issue: Password reset email not received

  • Cause: Email service not configured
  • Solution: Check SMTP settings or use admin password reset

Issue: GDPR export takes too long

  • Cause: Large amount of user data
  • Solution: Implement background job processing

Competitive Advantages

  1. GDPR Built-In - Full compliance out-of-the-box
  2. Enterprise Security - Industry-standard JWT + bcrypt
  3. Audit Trail - Complete authentication history
  4. Multi-Tenant Ready - Isolated user authentication
  5. Scalable - Handle thousands of concurrent users
  6. Event-Driven - Integration-ready with RabbitMQ
  7. EU Compliant - Designed for Spanish/EU market

Future Enhancements

  • Multi-Factor Authentication (MFA) - TOTP, SMS, email
  • Social Login - Google, Facebook, Apple authentication
  • Biometric Auth - Fingerprint, Face ID
  • OAuth2/OpenID Connect - Standards-based SSO
  • Passwordless Auth - Magic links, WebAuthn
  • Session Management UI - View and revoke active sessions
  • Advanced Audit - ML-based anomaly detection

For VUE Madrid Business Plan: The Auth Service demonstrates enterprise-grade security and full GDPR compliance, critical for EU operations. The built-in audit logging and data protection features prevent costly fines (up to €20M for GDPR violations) and provide peace of mind for bakery owners. This is a key differentiator vs competitors who lack proper data protection.