Skip to content

Tenant Specific Authentication

Overview

The tenant engine workflow in this application is designed to handle multi-tenancy, ensuring that each tenant's data is isolated and that the correct database session is used for each authenticated user. This document explains how the tenant engine is integrated with the authentication process and how it manages database sessions.

Key Components

  1. Tenant Identification
  2. Database Session Management
  3. Repository and Service Initialization

Detailed Workflow

1. Tenant Identification

The tenant is identified during the authentication process:

  • For user authentication:
  • The user's account is retrieved or created during token validation.
  • The account contains the tenant information.
  • For machine (service client) authentication:
  • The account is fetched based on the client_id in the token.
  • The tenant is derived from this account.

2. Database Session Management

Once the tenant is identified, the appropriate database session is created:

def get_tenant_session(
    user_with_account: UserWithAccount = Depends(validate_token),
) -> Session:
    tenant_id = user_with_account.account.tenant
    db_generator = get_tenant_db(tenant_id)
    db = next(db_generator)
    try:
        yield db
    finally:
        db_generator.close()

This function:

  • Takes a UserWithAccount object, which is obtained from the token validation process.
  • Extracts the tenant ID from the user's account.
  • Uses get_tenant_db(tenant_id) to create a database session specific to that tenant.
  • Yields the session for use in the request.
  • Ensures the session is closed after the request is completed.

3. Repository and Service Initialization

The tenant-specific database session is then used to initialize repositories and services:

def get_repository(repo_class):
    def _get_repo(db: Session = Depends(get_tenant_session)):
        return repo_class(db)
    return _get_repo

def get_service(service_class, repo_class):
    def _get_service(db: Session = Depends(get_tenant_session)):
        repo = repo_class(db)
        return service_class(repo)
    return _get_service

These functions:

  • Use dependency injection to get the tenant-specific database session.
  • Create repositories and services with the correct database session.
  • Ensure that all database operations are performed in the context of the correct tenant.

Integration with FastAPI

The tenant engine is seamlessly integrated with FastAPI's dependency injection system:

  1. The validate_token dependency identifies the user and their associated tenant.
  2. The get_tenant_session dependency uses this information to create the appropriate database session.
  3. Repository and service dependencies use get_tenant_session to ensure they operate on the correct tenant's data.

This tenant engine workflow ensures that your application can securely and efficiently handle multiple tenants, providing a robust foundation for multi-tenant applications.