flip_api.auth.access_manager

Attributes

API_KEY_HEADER_NAME

api_key_header_scheme

_trust_api_key_hashes_cache

INTERNAL_SERVICE_KEY_HEADER_NAME

internal_key_header_scheme

_internal_service_key_hash_cache

Functions

can_access_project(→ bool)

Check if a user has access to a specific project.

can_modify_project(→ bool)

Check if a user can perform project-level write operations (edit / stage / delete the project itself).

can_contribute_to_project(→ bool)

Check if a user can contribute artefacts (e.g. models) to a project.

can_modify_model(→ bool)

Check if a user can perform write operations on a model.

can_access_model(→ bool)

Check if a user has access to a specific model.

can_access_cohort_query(→ bool)

Check if the user has access to the specified cohort query.

verify_trust_identity(→ None)

Verify the authenticated trust matches the expected trust name.

_get_trust_api_key_hashes(→ dict[str, str])

Get trust API key hashes from env var (dev) or AWS Secrets Manager (prod).

_get_internal_service_key_hash(→ str)

Get internal service key hash from env var (dev) or AWS Secrets Manager (prod).

authenticate_internal_service() → None)

Authenticate an internal service (e.g., fl-server on the Central Hub).

authenticate_trust() → str)

Authenticate a trust by its per-trust API key and return the trust name.

Module Contents

flip_api.auth.access_manager.can_access_project(user_id: uuid.UUID, project_id: uuid.UUID, db: sqlmodel.Session) bool

Check if a user has access to a specific project.

Parameters:
  • user_id (UUID) – ID of the user

  • project_id (UUID) – ID of the project

  • db (Session) – Database session

Returns:

True if the user has access to the project, False otherwise

Return type:

bool

flip_api.auth.access_manager.can_modify_project(user_id: uuid.UUID, project_id: uuid.UUID, db: sqlmodel.Session) bool

Check if a user can perform project-level write operations (edit / stage / delete the project itself).

Returns True for Admins (CAN_MANAGE_PROJECTS) and the project owner. Project membership alone does NOT unlock project-level writes — see can_contribute_to_project() for the looser check used by model-write endpoints.

Parameters:
  • user_id (UUID) – ID of the user

  • project_id (UUID) – ID of the project

  • db (Session) – Database session

Returns:

True if the user can modify the project, False otherwise

Return type:

bool

flip_api.auth.access_manager.can_contribute_to_project(user_id: uuid.UUID, project_id: uuid.UUID, db: sqlmodel.Session) bool

Check if a user can contribute artefacts (e.g. models) to a project.

Looser than can_modify_project(): a Researcher who has been added to a project via ProjectUserAccess can contribute their own models even though they cannot edit the project itself. Observers — who hold no permissions — are excluded by the CAN_CREATE_PROJECTS clause, so membership alone does not unlock writes for them.

Returns True when any of the following holds:
  • The caller has CAN_MANAGE_PROJECTS (Admin), or

  • The caller is the project owner, or

  • The caller has a ProjectUserAccess row for the project AND holds CAN_CREATE_PROJECTS (Researcher member).

Parameters:
  • user_id (UUID) – ID of the user

  • project_id (UUID) – ID of the project

  • db (Session) – Database session

Returns:

True if the user can contribute to the project, False otherwise.

Return type:

bool

flip_api.auth.access_manager.can_modify_model(user_id: uuid.UUID, model_id: uuid.UUID, db: sqlmodel.Session) bool

Check if a user can perform write operations on a model.

Allows:
  • Admins (CAN_MANAGE_PROJECTS).

  • The project owner (unrestricted across all models on the project).

  • The model’s own owner_id, but only if they could still contribute to the project (per can_contribute_to_project()). The contribution check is defence-in-depth: it locks an Observer out even if they somehow ended up as Model.owner_id.

Parameters:
  • user_id (UUID) – ID of the user

  • model_id (UUID) – ID of the model

  • db (Session) – Database session

Returns:

True if the user can modify the model, False otherwise

Return type:

bool

flip_api.auth.access_manager.can_access_model(user_id: uuid.UUID, model_id: uuid.UUID, db: sqlmodel.Session) bool

Check if a user has access to a specific model.

Parameters:
  • user_id (UUID) – ID of the user

  • model_id (UUID) – ID of the model

  • db (Session) – Database session

Returns:

True if the user has access to the model, False otherwise

Return type:

bool

Raises:

HTTPException – If there is an error during the access check

flip_api.auth.access_manager.can_access_cohort_query(user_id: uuid.UUID, query_id: uuid.UUID, db: sqlmodel.Session) bool

Check if the user has access to the specified cohort query.

Parameters:
  • user_id (UUID) – ID of the user

  • query_id (UUID) – ID of the cohort query

  • db (Session) – Database session

Returns:

True if the user has access to the cohort query, False otherwise

Return type:

bool

Raises:

HTTPException – If there is an error during the access check

flip_api.auth.access_manager.API_KEY_HEADER_NAME
flip_api.auth.access_manager.api_key_header_scheme
flip_api.auth.access_manager.verify_trust_identity(trust_name: str, authenticated_trust: str) None

Verify the authenticated trust matches the expected trust name.

Parameters:
  • trust_name (str) – The trust name from the URL path.

  • authenticated_trust (str) – The trust name from API key authentication.

Raises:

HTTPException – 403 if the names do not match.

flip_api.auth.access_manager._trust_api_key_hashes_cache: dict[str, str] | None = None
flip_api.auth.access_manager._get_trust_api_key_hashes() dict[str, str]

Get trust API key hashes from env var (dev) or AWS Secrets Manager (prod).

Cached after first call — the hashes do not change during the lifetime of a process.

Returns:

Mapping of trust names to SHA-256 hex digests of their API keys.

Return type:

dict[str, str]

flip_api.auth.access_manager.INTERNAL_SERVICE_KEY_HEADER_NAME
flip_api.auth.access_manager.internal_key_header_scheme
flip_api.auth.access_manager._internal_service_key_hash_cache: str | None = None
flip_api.auth.access_manager._get_internal_service_key_hash() str

Get internal service key hash from env var (dev) or AWS Secrets Manager (prod).

Cached after first call — the hash does not change during the lifetime of a process.

Returns:

SHA-256 hex digest of the internal service key, or empty string if not configured.

Return type:

str

flip_api.auth.access_manager.authenticate_internal_service(api_key: str = Security(internal_key_header_scheme)) None

Authenticate an internal service (e.g., fl-server on the Central Hub).

The fl-server sends an internal service key in the X-Internal-Service-Key header. This dependency hashes the provided key and compares it against the stored hash using constant-time comparison.

Parameters:

api_key (str) – The internal service key from the request header.

Raises:

HTTPException – 401 if the key is missing, unconfigured, or invalid.

flip_api.auth.access_manager.authenticate_trust(api_key: str = Security(api_key_header_scheme)) str

Authenticate a trust by its per-trust API key and return the trust name.

Each trust has a unique API key. The hub stores SHA-256 hashes of these keys in TRUST_API_KEY_HASHES (env var in dev, AWS Secrets Manager in prod). This dependency hashes the provided key, looks it up in the mapping, and returns the authenticated trust name.

Uses hmac.compare_digest for constant-time comparison to prevent timing attacks.

Parameters:

api_key (str) – The API key extracted from the request header.

Raises:

HTTPException – 401 if the key is missing or does not match any trust.

Returns:

The name of the authenticated trust (e.g. “Trust_1”).

Return type:

str