"""Authentik service definition. Authentik is the user-directory source (replacing the Jellyfin-backed Users page). Its directory API is queried via :class:`AuthentikClient` and surfaced on the Authentik service page (Users + Messaging tabs). OIDC authentication is unchanged -- this service type is for the directory, not SSO. """ from __future__ import annotations from typing import TYPE_CHECKING, Any from media_library_viewer_api.clients.authentik import AuthentikClient from media_library_viewer_api.integrations.base import ( SecretField, ServiceBaseUrl, ServiceConfigBase, ServiceDefinition, TestResult, translate_connection_error, ) if TYPE_CHECKING: from media_library_viewer_api.services.settings_store import SettingsStore def test_connection( config: dict[str, Any], secrets: dict[str, str], store: SettingsStore, ) -> TestResult: """Probe AuthentikClient.users(page=1, page_size=1) — lightest directory call.""" try: base_url = str(config.get("base_url") or "").rstrip("/") api_token = str(secrets.get("api_token") or "") timeout = float(config.get("timeout_seconds") or 60) client = AuthentikClient(base_url=base_url, api_token=api_token, timeout=timeout) result = client.users(page=1, page_size=1) total = result.get("total", 0) if isinstance(result, dict) else 0 return TestResult(ok=True, detail="Connected to Authentik.", evidence=f"{total} users") except Exception as exc: return translate_connection_error(exc, context="Authentik") class AuthentikConfig(ServiceConfigBase): """Non-secret Authentik connection config.""" base_url: ServiceBaseUrl timeout_seconds: int = 60 DEFINITION = ServiceDefinition( service_type="authentik", name="Authentik", description="User directory and identity provider integration.", config_model=AuthentikConfig, secret_fields=[ SecretField(key="api_token", label="API token", required=True), ], widget_kinds=[], test_callable=test_connection, )