Source code for qfa.adapters.env_auth

"""Environment-based authentication lookup adapter."""

from qfa.domain.models import AuthKeyInfo, TenantApiKey
from qfa.domain.ports import AuthLookupPort


[docs] class EnvironmentAuthLookupAdapter(AuthLookupPort): """AuthLookupPort implementation backed by a static list of API keys. Keys are injected at construction time (e.g. loaded from the ``AUTH_API_KEYS`` environment variable via ``AuthSettings``). No external I/O is performed; every lookup is an in-process scan. Parameters ---------- api_keys : list[TenantApiKey] The full set of valid API keys to validate against. """ def __init__(self, api_keys: list[TenantApiKey]) -> None: self._api_keys = list(api_keys)
[docs] async def validate_api_key(self, provided_key: str) -> TenantApiKey | None: """Return the matching TenantApiKey, or None if no key matches. Uses ``TenantApiKey.matches_key`` (``secrets.compare_digest``) for constant-time comparison and always iterates **all** keys to avoid leaking information about how many keys are registered. Parameters ---------- provided_key : str The API key value supplied by the caller. Returns ------- TenantApiKey | None The matching tenant API key, or ``None`` if no match was found. """ match: TenantApiKey | None = None for api_key in self._api_keys: if api_key.matches_key(provided_key): match = api_key return match
[docs] async def get_auth_keys(self, tenant_id: str | None = None) -> list[AuthKeyInfo]: """Return API key metadata for the given tenant, or all tenants. Sensitive fields (``hashed_key``) are excluded from the returned dicts. Parameters ---------- tenant_id : str | None Filter by this tenant identifier, or ``None`` to return keys for all tenants. Returns ------- list[AuthKeyInfo] A list of AuthKeyInfo objects with auth key information (no secret values). """ keys = ( self._api_keys if tenant_id is None else [k for k in self._api_keys if k.tenant_id == tenant_id] ) return [AuthKeyInfo(**k.model_dump(exclude={"hashed_key"})) for k in keys]