authentik.root.settings

root settings for authentik

  1"""root settings for authentik"""
  2
  3import importlib
  4from collections import OrderedDict
  5from hashlib import sha512
  6from pathlib import Path
  7
  8import orjson
  9from django.utils import http as utils_http
 10from sentry_sdk import set_tag
 11from xmlsec import enable_debug_trace
 12
 13from authentik import authentik_version
 14from authentik.lib.config import CONFIG, django_db_config
 15from authentik.lib.logging import get_logger_config, structlog_configure
 16from authentik.lib.sentry import sentry_init
 17from authentik.lib.utils.reflection import get_env
 18from authentik.lib.utils.time import timedelta_from_string
 19from authentik.stages.password import BACKEND_APP_PASSWORD, BACKEND_INBUILT, BACKEND_LDAP
 20
 21BASE_DIR = Path(__file__).absolute().parent.parent.parent
 22
 23DEBUG = CONFIG.get_bool("debug")
 24SECRET_KEY = CONFIG.get("secret_key")
 25
 26INTERNAL_IPS = ["127.0.0.1"]
 27ALLOWED_HOSTS = ["*"]
 28SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
 29SECURE_CROSS_ORIGIN_OPENER_POLICY = None
 30LOGIN_URL = "authentik_flows:default-authentication"
 31
 32# Custom user model
 33AUTH_USER_MODEL = "authentik_core.User"
 34
 35CSRF_COOKIE_PATH = LANGUAGE_COOKIE_PATH = SESSION_COOKIE_PATH = CONFIG.get("web.path", "/")
 36
 37CSRF_COOKIE_NAME = "authentik_csrf"
 38CSRF_HEADER_NAME = "HTTP_X_AUTHENTIK_CSRF"
 39LANGUAGE_COOKIE_NAME = "authentik_language"
 40SESSION_COOKIE_NAME = "authentik_session"
 41SESSION_COOKIE_DOMAIN = CONFIG.get("cookie_domain", None)
 42APPEND_SLASH = False
 43
 44AUTHENTICATION_BACKENDS = [
 45    BACKEND_INBUILT,
 46    BACKEND_APP_PASSWORD,
 47    BACKEND_LDAP,
 48    "guardian.backends.ObjectPermissionBackend",
 49]
 50
 51DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
 52
 53# Application definition
 54SHARED_APPS = [
 55    "authentik.commands",
 56    "django_tenants",
 57    "authentik.tenants",
 58    "django.contrib.messages",
 59    "django.contrib.staticfiles",
 60    "django.contrib.humanize",
 61    "django.contrib.postgres",
 62    "psqlextra",
 63    "rest_framework",
 64    "django_filters",
 65    "drf_spectacular",
 66    "django_prometheus",
 67    "django_countries",
 68    "pgactivity",
 69    "pglock",
 70    "channels",
 71    "django_channels_postgres",
 72    "django_dramatiq_postgres",
 73    "authentik.tasks",
 74]
 75TENANT_APPS = [
 76    "django.contrib.auth",
 77    "django.contrib.contenttypes",
 78    "django.contrib.sessions",
 79    "pgtrigger",
 80    "django_postgres_cache",
 81    "authentik.admin",
 82    "authentik.api",
 83    "authentik.core",
 84    "authentik.crypto",
 85    "authentik.endpoints",
 86    "authentik.endpoints.connectors.agent",
 87    "authentik.events",
 88    "authentik.admin.files",
 89    "authentik.flows",
 90    "authentik.outposts",
 91    "authentik.policies.dummy",
 92    "authentik.policies.event_matcher",
 93    "authentik.policies.expiry",
 94    "authentik.policies.expression",
 95    "authentik.policies.geoip",
 96    "authentik.policies.password",
 97    "authentik.policies.reputation",
 98    "authentik.policies",
 99    "authentik.providers.ldap",
100    "authentik.providers.oauth2",
101    "authentik.providers.proxy",
102    "authentik.providers.rac",
103    "authentik.providers.radius",
104    "authentik.providers.saml",
105    "authentik.providers.scim",
106    "authentik.rbac",
107    "authentik.recovery",
108    "authentik.sources.kerberos",
109    "authentik.sources.ldap",
110    "authentik.sources.oauth",
111    "authentik.sources.plex",
112    "authentik.sources.saml",
113    "authentik.sources.scim",
114    "authentik.sources.telegram",
115    "authentik.stages.authenticator",
116    "authentik.stages.authenticator_duo",
117    "authentik.stages.authenticator_email",
118    "authentik.stages.authenticator_sms",
119    "authentik.stages.authenticator_static",
120    "authentik.stages.authenticator_totp",
121    "authentik.stages.authenticator_validate",
122    "authentik.stages.authenticator_webauthn",
123    "authentik.stages.captcha",
124    "authentik.stages.consent",
125    "authentik.stages.deny",
126    "authentik.stages.dummy",
127    "authentik.stages.email",
128    "authentik.stages.identification",
129    "authentik.stages.invitation",
130    "authentik.stages.password",
131    "authentik.stages.prompt",
132    "authentik.stages.redirect",
133    "authentik.stages.user_delete",
134    "authentik.stages.user_login",
135    "authentik.stages.user_logout",
136    "authentik.stages.user_write",
137    "authentik.tasks.schedules",
138    "authentik.brands",
139    "authentik.blueprints",
140    "guardian",
141]
142
143TENANT_MODEL = "authentik_tenants.Tenant"
144TENANT_DOMAIN_MODEL = "authentik_tenants.Domain"
145
146TENANT_CREATION_FAKES_MIGRATIONS = True
147TENANT_BASE_SCHEMA = "template"
148PUBLIC_SCHEMA_NAME = CONFIG.get("postgresql.default_schema")
149
150GUARDIAN_GROUP_MODEL = "authentik_core.Group"
151GUARDIAN_ROLE_MODEL = "authentik_rbac.Role"
152
153SPECTACULAR_SETTINGS = {
154    "TITLE": "authentik",
155    "DESCRIPTION": "Making authentication simple.",
156    "VERSION": authentik_version(),
157    "COMPONENT_SPLIT_REQUEST": True,
158    "SCHEMA_PATH_PREFIX": "/api/v([0-9]+(beta)?)",
159    "SCHEMA_PATH_PREFIX_TRIM": True,
160    "SERVERS": [
161        {
162            "url": "/api/v3",
163        },
164    ],
165    "CONTACT": {
166        "email": "hello@goauthentik.io",
167    },
168    "AUTHENTICATION_WHITELIST": ["authentik.api.authentication.TokenAuthentication"],
169    "LICENSE": {
170        "name": "MIT",
171        "url": "https://github.com/goauthentik/authentik/blob/main/LICENSE",
172    },
173    "ENUM_NAME_OVERRIDES": {
174        "AppEnum": "authentik.lib.api.Apps",
175        "AuthenticationEnum": "authentik.flows.models.FlowAuthenticationRequirement",
176        "ConsentModeEnum": "authentik.stages.consent.models.ConsentMode",
177        "CountryCodeEnum": "django_countries.countries",
178        "DeviceClassesEnum": "authentik.stages.authenticator_validate.models.DeviceClasses",
179        "DeviceFactsOSFamily": "authentik.endpoints.facts.OSFamily",
180        "EventActions": "authentik.events.models.EventAction",
181        "FlowDesignationEnum": "authentik.flows.models.FlowDesignation",
182        "FlowLayoutEnum": "authentik.flows.models.FlowLayout",
183        "LDAPAPIAccessMode": "authentik.providers.ldap.models.APIAccessMode",
184        "ModelEnum": "authentik.lib.api.Models",
185        "OutgoingSyncDeleteAction": "authentik.lib.sync.outgoing.models.OutgoingSyncDeleteAction",
186        "PKCEMethodEnum": "authentik.sources.oauth.models.PKCEMethod",
187        "PolicyEngineMode": "authentik.policies.models.PolicyEngineMode",
188        "PromptTypeEnum": "authentik.stages.prompt.models.FieldTypes",
189        "ProxyMode": "authentik.providers.proxy.models.ProxyMode",
190        "RedirectURITypeEnum": "authentik.providers.oauth2.models.RedirectURIType",
191        "SAMLBindingsEnum": "authentik.providers.saml.models.SAMLBindings",
192        "SAMLLogoutMethods": "authentik.providers.saml.models.SAMLLogoutMethods",
193        "SAMLNameIDPolicyEnum": "authentik.sources.saml.models.SAMLNameIDPolicy",
194        "SCIMAuthenticationModeEnum": "authentik.providers.scim.models.SCIMAuthenticationMode",
195        "StageModeEnum": "authentik.endpoints.models.StageMode",
196        "TaskAggregatedStatusEnum": "authentik.tasks.models.TaskStatus",
197        "TaskStatusEnum": "django_dramatiq_postgres.models.TaskState",
198        "TransportModeEnum": "authentik.events.models.TransportMode",
199        "UserTypeEnum": "authentik.core.models.UserTypes",
200        "UserVerificationEnum": "authentik.stages.authenticator_webauthn.models.UserVerification",
201        "WebAuthnHintEnum": "authentik.stages.authenticator_webauthn.models.WebAuthnHint",
202    },
203    "ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE": False,
204    "ENUM_GENERATE_CHOICE_DESCRIPTION": False,
205    "PREPROCESSING_HOOKS": [
206        "authentik.api.v3.schema.cleanup.preprocess_schema_exclude_non_api",
207    ],
208    "POSTPROCESSING_HOOKS": [
209        "authentik.api.v3.schema.response.postprocess_schema_register",
210        "authentik.api.v3.schema.response.postprocess_schema_responses",
211        "authentik.api.v3.schema.query.postprocess_schema_query_params",
212        "authentik.api.v3.schema.cleanup.postprocess_schema_remove_unused",
213        "authentik.api.v3.schema.search.postprocess_schema_search_autocomplete",
214        "authentik.api.v3.schema.enum.postprocess_schema_enums",
215    ],
216}
217
218REST_FRAMEWORK = {
219    "DEFAULT_PAGINATION_CLASS": "authentik.api.pagination.Pagination",
220    "DEFAULT_FILTER_BACKENDS": [
221        "authentik.api.search.ql.QLSearch",
222        "authentik.rbac.filters.ObjectFilter",
223        "django_filters.rest_framework.DjangoFilterBackend",
224        "authentik.api.ordering.NullsAwareOrderingFilter",
225    ],
226    "DEFAULT_PERMISSION_CLASSES": ("authentik.rbac.permissions.ObjectPermissions",),
227    "DEFAULT_AUTHENTICATION_CLASSES": (
228        "authentik.api.authentication.TokenAuthentication",
229        "rest_framework.authentication.SessionAuthentication",
230    ),
231    "DEFAULT_RENDERER_CLASSES": [
232        "drf_orjson_renderer.renderers.ORJSONRenderer",
233    ],
234    "ORJSON_RENDERER_OPTIONS": [
235        orjson.OPT_NON_STR_KEYS,
236        orjson.OPT_UTC_Z,
237    ],
238    "DEFAULT_PARSER_CLASSES": [
239        "drf_orjson_renderer.parsers.ORJSONParser",
240    ],
241    "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
242    "TEST_REQUEST_DEFAULT_FORMAT": "json",
243    "DEFAULT_THROTTLE_CLASSES": ["rest_framework.throttling.AnonRateThrottle"],
244    "DEFAULT_THROTTLE_RATES": {
245        "anon": CONFIG.get("throttle.default"),
246    },
247}
248
249
250CACHES = {
251    "default": {
252        "BACKEND": "django_postgres_cache.backend.DatabaseCache",
253        "KEY_FUNCTION": "django_tenants.cache.make_key",
254        "REVERSE_KEY_FUNCTION": "django_tenants.cache.reverse_key",
255    }
256}
257SESSION_ENGINE = "authentik.core.sessions"
258# Configured via custom SessionMiddleware
259# SESSION_COOKIE_SAMESITE = "None"
260# SESSION_COOKIE_SECURE = True
261SESSION_COOKIE_AGE = timedelta_from_string(
262    CONFIG.get("sessions.unauthenticated_age", "days=1")
263).total_seconds()
264SESSION_EXPIRE_AT_BROWSER_CLOSE = True
265
266MESSAGE_STORAGE = "authentik.root.ws.storage.ChannelsStorage"
267
268MIDDLEWARE_FIRST = [
269    "django_prometheus.middleware.PrometheusBeforeMiddleware",
270]
271MIDDLEWARE = [
272    "authentik.tenants.middleware.DefaultTenantMiddleware",
273    "authentik.root.middleware.LoggingMiddleware",
274    "authentik.root.middleware.ClientIPMiddleware",
275    "authentik.stages.user_login.middleware.BoundSessionMiddleware",
276    "django.middleware.locale.LocaleMiddleware",
277    "authentik.core.middleware.AuthenticationMiddleware",
278    "authentik.core.middleware.RequestIDMiddleware",
279    "authentik.brands.middleware.BrandMiddleware",
280    "authentik.events.middleware.AuditMiddleware",
281    "django.middleware.security.SecurityMiddleware",
282    "django.middleware.common.CommonMiddleware",
283    "authentik.root.middleware.CsrfViewMiddleware",
284    "django.contrib.messages.middleware.MessageMiddleware",
285    "django.middleware.clickjacking.XFrameOptionsMiddleware",
286    "authentik.core.middleware.ImpersonateMiddleware",
287    "authentik.rbac.middleware.InitialPermissionsMiddleware",
288]
289MIDDLEWARE_LAST = [
290    "django_prometheus.middleware.PrometheusAfterMiddleware",
291]
292
293ROOT_URLCONF = "authentik.root.urls"
294
295TEMPLATES = [
296    {
297        "BACKEND": "django.template.backends.django.DjangoTemplates",
298        "DIRS": [CONFIG.get("email.template_dir")],
299        "APP_DIRS": True,
300        "OPTIONS": {
301            "context_processors": [
302                "django.template.context_processors.debug",
303                "django.template.context_processors.request",
304                "django.contrib.auth.context_processors.auth",
305                "django.contrib.messages.context_processors.messages",
306                "authentik.brands.utils.context_processor",
307            ],
308        },
309    },
310]
311
312ASGI_APPLICATION = "authentik.root.asgi.application"
313
314
315# Database
316# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
317
318# Custom overrides for database backends
319# The tree looks like this:
320# psqlextra backend
321#   -> authentik custom backend
322#     -> django_tenants backend
323#       -> django_prometheus backend
324#         -> django built-in backend
325ORIGINAL_BACKEND = "django_prometheus.db.backends.postgresql"
326POSTGRES_EXTRA_DB_BACKEND_BASE = "authentik.root.db"
327DATABASES = django_db_config()
328
329DATABASE_ROUTERS = (
330    "authentik.tenants.db.FailoverRouter",
331    "django_tenants.routers.TenantSyncRouter",
332)
333
334# We don't use HStore
335POSTGRES_EXTRA_AUTO_EXTENSION_SET_UP = False
336
337CHANNEL_LAYERS = {
338    "default": {
339        "BACKEND": "django_channels_postgres.layer.PostgresChannelLayer",
340    },
341}
342
343# Email
344# These values should never actually be used, emails are only sent from email stages, which
345# loads the config directly from CONFIG
346# See authentik/stages/email/models.py, line 105
347EMAIL_HOST = CONFIG.get("email.host")
348EMAIL_PORT = CONFIG.get_int("email.port")
349EMAIL_HOST_USER = CONFIG.get("email.username")
350EMAIL_HOST_PASSWORD = CONFIG.get("email.password")
351EMAIL_USE_TLS = CONFIG.get_bool("email.use_tls", False)
352EMAIL_USE_SSL = CONFIG.get_bool("email.use_ssl", False)
353EMAIL_TIMEOUT = CONFIG.get_int("email.timeout")
354DEFAULT_FROM_EMAIL = CONFIG.get("email.from")
355SERVER_EMAIL = DEFAULT_FROM_EMAIL
356EMAIL_SUBJECT_PREFIX = "[authentik] "
357
358# Password validation
359# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
360
361AUTH_PASSWORD_VALIDATORS = [
362    {
363        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
364    },
365    {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
366    {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
367    {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
368]
369
370
371# Internationalization
372# https://docs.djangoproject.com/en/2.1/topics/i18n/
373
374LANGUAGE_CODE = "en-us"
375
376TIME_ZONE = "UTC"
377
378USE_I18N = True
379
380USE_TZ = True
381
382LOCALE_PATHS = ["./locale"]
383
384
385# Tests
386
387TEST = False
388TEST_RUNNER = "authentik.root.test_runner.PytestTestRunner"
389
390
391# Dramatiq
392
393DRAMATIQ = {
394    "broker_class": "authentik.tasks.broker.Broker",
395    "channel_prefix": "authentik",
396    "task_model": "authentik.tasks.models.Task",
397    "task_purge_interval": timedelta_from_string(
398        CONFIG.get("worker.task_purge_interval")
399    ).total_seconds(),
400    "task_expiration": timedelta_from_string(CONFIG.get("worker.task_expiration")).total_seconds(),
401    "autodiscovery": {
402        "enabled": True,
403        "setup_module": "authentik.tasks.setup",
404        "apps_prefix": "authentik",
405    },
406    "worker": {
407        "processes": CONFIG.get_int("worker.processes", 2),
408        "threads": CONFIG.get_int("worker.threads", 1),
409        "consumer_listen_timeout": timedelta_from_string(
410            CONFIG.get("worker.consumer_listen_timeout")
411        ).total_seconds(),
412        "watch_folder": BASE_DIR / "authentik",
413    },
414    "scheduler_class": "authentik.tasks.schedules.scheduler.Scheduler",
415    "schedule_model": "authentik.tasks.schedules.models.Schedule",
416    "scheduler_interval": timedelta_from_string(
417        CONFIG.get("worker.scheduler_interval")
418    ).total_seconds(),
419    "middlewares": (
420        ("django_dramatiq_postgres.middleware.FullyQualifiedActorName", {}),
421        ("django_dramatiq_postgres.middleware.DbConnectionMiddleware", {}),
422        ("django_dramatiq_postgres.middleware.TaskStateBeforeMiddleware", {}),
423        ("dramatiq.middleware.age_limit.AgeLimit", {}),
424        (
425            "dramatiq.middleware.time_limit.TimeLimit",
426            {
427                "time_limit": timedelta_from_string(
428                    CONFIG.get("worker.task_default_time_limit")
429                ).total_seconds()
430                * 1000
431            },
432        ),
433        ("dramatiq.middleware.shutdown.ShutdownNotifications", {}),
434        ("dramatiq.middleware.callbacks.Callbacks", {}),
435        ("dramatiq.middleware.pipelines.Pipelines", {}),
436        (
437            "dramatiq.middleware.retries.Retries",
438            {
439                "max_retries": CONFIG.get_int("worker.task_max_retries") if not TEST else 0,
440                "max_backoff": 60 * 60 * 1000,  # 1 hour
441            },
442        ),
443        ("dramatiq.results.middleware.Results", {"store_results": True}),
444        ("authentik.tasks.middleware.StartupSignalsMiddleware", {}),
445        ("authentik.tasks.middleware.CurrentTask", {}),
446        ("authentik.tasks.middleware.TenantMiddleware", {}),
447        ("authentik.tasks.middleware.ModelDataMiddleware", {}),
448        ("authentik.tasks.middleware.TaskLogMiddleware", {}),
449        ("authentik.tasks.middleware.LoggingMiddleware", {}),
450        ("authentik.tasks.middleware.DescriptionMiddleware", {}),
451        (
452            "authentik.tasks.middleware.MetricsMiddleware",
453            {
454                "prefix": "authentik",
455            },
456        ),
457        ("django_dramatiq_postgres.middleware.TaskStateAfterMiddleware", {}),
458    ),
459    "test": TEST,
460}
461
462
463# Sentry integration
464
465env = get_env()
466_ERROR_REPORTING = CONFIG.get_bool("error_reporting.enabled", False)
467if _ERROR_REPORTING:
468    sentry_env = CONFIG.get("error_reporting.environment", "customer")
469    sentry_init(spotlight=DEBUG)
470    set_tag("authentik.uuid", sha512(str(SECRET_KEY).encode("ascii")).hexdigest()[:16])
471
472
473# Static files (CSS, JavaScript, Images)
474# https://docs.djangoproject.com/en/2.1/howto/static-files/
475
476STATICFILES_DIRS = [BASE_DIR / Path("web")]
477STATIC_URL = CONFIG.get("web.path", "/") + "static/"
478
479STORAGES = {
480    "staticfiles": {
481        "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
482    },
483}
484
485# Django 5.2.8 and CVE-2025-64458 added a strong enforcement of 2048 characters
486# as the maximum for a URL to redirect to, mostly for running on Windows.
487# However, our URLs can easily exceed that with OAuth/SAML Query parameters or hash values.
488# 8192 should cover most cases.
489utils_http.MAX_URL_LENGTH = utils_http.MAX_URL_LENGTH * 4
490
491structlog_configure()
492LOGGING = get_logger_config()
493
494
495_DISALLOWED_ITEMS = [
496    "SHARED_APPS",
497    "TENANT_APPS",
498    "INSTALLED_APPS",
499    "MIDDLEWARE_FIRST",
500    "MIDDLEWARE",
501    "MIDDLEWARE_LAST",
502    "AUTHENTICATION_BACKENDS",
503    "SPECTACULAR_SETTINGS",
504    "REST_FRAMEWORK",
505]
506
507SILENCED_SYSTEM_CHECKS = [
508    # We use our own subclass of django.middleware.csrf.CsrfViewMiddleware
509    "security.W003",
510    # We don't set SESSION_COOKIE_SECURE since we use a custom SessionMiddleware subclass
511    "security.W010",
512    # HSTS: This is configured in reverse proxies/the go proxy, not in django
513    "security.W004",
514    # https redirect: This is configured in reverse proxies/the go proxy, not in django
515    "security.W008",
516]
517
518
519def subtract_list(a: list, b: list) -> list:
520    return [item for item in a if item not in b]
521
522
523def _filter_and_update(apps: list[str]) -> None:
524    for _app in set(apps):
525        if not _app.startswith("authentik"):
526            continue
527        _update_settings(f"{_app}.settings")
528
529
530def _update_settings(app_path: str) -> None:
531    try:
532        settings_module = importlib.import_module(app_path)
533        CONFIG.log("debug", "Loaded app settings", path=app_path)
534
535        new_shared_apps = subtract_list(getattr(settings_module, "SHARED_APPS", []), SHARED_APPS)
536        new_tenant_apps = subtract_list(getattr(settings_module, "TENANT_APPS", []), TENANT_APPS)
537        SHARED_APPS.extend(new_shared_apps)
538        TENANT_APPS.extend(new_tenant_apps)
539        _filter_and_update(new_shared_apps + new_tenant_apps)
540
541        MIDDLEWARE_FIRST.extend(getattr(settings_module, "MIDDLEWARE_FIRST", []))
542        MIDDLEWARE.extend(getattr(settings_module, "MIDDLEWARE", []))
543
544        AUTHENTICATION_BACKENDS.extend(getattr(settings_module, "AUTHENTICATION_BACKENDS", []))
545        SPECTACULAR_SETTINGS.update(getattr(settings_module, "SPECTACULAR_SETTINGS", {}))
546        REST_FRAMEWORK.update(getattr(settings_module, "REST_FRAMEWORK", {}))
547
548        for _attr in dir(settings_module):
549            if not _attr.startswith("__") and _attr not in _DISALLOWED_ITEMS:
550                globals()[_attr] = getattr(settings_module, _attr)
551    except ImportError:
552        pass
553
554
555# Attempt to load enterprise app, if available
556try:
557    importlib.import_module("authentik.enterprise.apps")
558    CONFIG.log("info", "Enabled authentik enterprise")
559    TENANT_APPS.insert(TENANT_APPS.index("authentik.events"), "authentik.enterprise")
560except ImportError:
561    pass
562
563
564if DEBUG:
565    REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"].append(
566        "rest_framework.renderers.BrowsableAPIRenderer"
567    )
568    SHARED_APPS.insert(SHARED_APPS.index("django.contrib.staticfiles"), "daphne")
569    enable_debug_trace(True)
570
571
572CONFIG.log("info", "Booting authentik", version=authentik_version())
573
574# Load subapps's settings
575_filter_and_update(SHARED_APPS + TENANT_APPS)
576_update_settings("data.user_settings")
577
578MIDDLEWARE = list(OrderedDict.fromkeys(MIDDLEWARE_FIRST + MIDDLEWARE + MIDDLEWARE_LAST))
579SHARED_APPS = list(OrderedDict.fromkeys(SHARED_APPS + TENANT_APPS))
580INSTALLED_APPS = list(OrderedDict.fromkeys(SHARED_APPS + TENANT_APPS))
BASE_DIR = PosixPath('/home/runner/work/authentik/authentik')
DEBUG = False
SECRET_KEY = 'bTxssXkGczffpZo0gjyXqcJQlJUu7VSqkEevXv8m'
INTERNAL_IPS = ['127.0.0.1']
ALLOWED_HOSTS = ['*']
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_CROSS_ORIGIN_OPENER_POLICY = None
LOGIN_URL = 'authentik_flows:default-authentication'
AUTH_USER_MODEL = 'authentik_core.User'
CSRF_HEADER_NAME = 'HTTP_X_AUTHENTIK_CSRF'
APPEND_SLASH = False
AUTHENTICATION_BACKENDS = ['authentik.core.auth.InbuiltBackend', 'authentik.core.auth.TokenBackend', 'authentik.sources.ldap.auth.LDAPBackend', 'guardian.backends.ObjectPermissionBackend']
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
SHARED_APPS = ['authentik.commands', 'django_tenants', 'authentik.tenants', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.humanize', 'django.contrib.postgres', 'psqlextra', 'rest_framework', 'django_filters', 'drf_spectacular', 'django_prometheus', 'django_countries', 'pgactivity', 'pglock', 'channels', 'django_channels_postgres', 'django_dramatiq_postgres', 'authentik.tasks', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'pgtrigger', 'django_postgres_cache', 'authentik.admin', 'authentik.api', 'authentik.core', 'authentik.crypto', 'authentik.endpoints', 'authentik.endpoints.connectors.agent', 'authentik.enterprise', 'authentik.events', 'authentik.admin.files', 'authentik.flows', 'authentik.outposts', 'authentik.policies.dummy', 'authentik.policies.event_matcher', 'authentik.policies.expiry', 'authentik.policies.expression', 'authentik.policies.geoip', 'authentik.policies.password', 'authentik.policies.reputation', 'authentik.policies', 'authentik.providers.ldap', 'authentik.providers.oauth2', 'authentik.providers.proxy', 'authentik.providers.rac', 'authentik.providers.radius', 'authentik.providers.saml', 'authentik.providers.scim', 'authentik.rbac', 'authentik.recovery', 'authentik.sources.kerberos', 'authentik.sources.ldap', 'authentik.sources.oauth', 'authentik.sources.plex', 'authentik.sources.saml', 'authentik.sources.scim', 'authentik.sources.telegram', 'authentik.stages.authenticator', 'authentik.stages.authenticator_duo', 'authentik.stages.authenticator_email', 'authentik.stages.authenticator_sms', 'authentik.stages.authenticator_static', 'authentik.stages.authenticator_totp', 'authentik.stages.authenticator_validate', 'authentik.stages.authenticator_webauthn', 'authentik.stages.captcha', 'authentik.stages.consent', 'authentik.stages.deny', 'authentik.stages.dummy', 'authentik.stages.email', 'authentik.stages.identification', 'authentik.stages.invitation', 'authentik.stages.password', 'authentik.stages.prompt', 'authentik.stages.redirect', 'authentik.stages.user_delete', 'authentik.stages.user_login', 'authentik.stages.user_logout', 'authentik.stages.user_write', 'authentik.tasks.schedules', 'authentik.brands', 'authentik.blueprints', 'guardian', 'authentik.enterprise.audit', 'authentik.enterprise.endpoints.connectors.agent', 'authentik.enterprise.endpoints.connectors.fleet', 'authentik.enterprise.endpoints.connectors.google_chrome', 'authentik.enterprise.lifecycle', 'authentik.enterprise.policies.unique_password', 'authentik.enterprise.providers.google_workspace', 'authentik.enterprise.providers.microsoft_entra', 'authentik.enterprise.providers.radius', 'authentik.enterprise.providers.scim', 'authentik.enterprise.providers.ssf', 'authentik.enterprise.providers.ws_federation', 'authentik.enterprise.reports', 'authentik.enterprise.stages.account_lockdown', 'authentik.enterprise.stages.authenticator_endpoint_gdtc', 'authentik.enterprise.stages.mtls', 'authentik.enterprise.stages.source']
TENANT_APPS = ['django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'pgtrigger', 'django_postgres_cache', 'authentik.admin', 'authentik.api', 'authentik.core', 'authentik.crypto', 'authentik.endpoints', 'authentik.endpoints.connectors.agent', 'authentik.enterprise', 'authentik.events', 'authentik.admin.files', 'authentik.flows', 'authentik.outposts', 'authentik.policies.dummy', 'authentik.policies.event_matcher', 'authentik.policies.expiry', 'authentik.policies.expression', 'authentik.policies.geoip', 'authentik.policies.password', 'authentik.policies.reputation', 'authentik.policies', 'authentik.providers.ldap', 'authentik.providers.oauth2', 'authentik.providers.proxy', 'authentik.providers.rac', 'authentik.providers.radius', 'authentik.providers.saml', 'authentik.providers.scim', 'authentik.rbac', 'authentik.recovery', 'authentik.sources.kerberos', 'authentik.sources.ldap', 'authentik.sources.oauth', 'authentik.sources.plex', 'authentik.sources.saml', 'authentik.sources.scim', 'authentik.sources.telegram', 'authentik.stages.authenticator', 'authentik.stages.authenticator_duo', 'authentik.stages.authenticator_email', 'authentik.stages.authenticator_sms', 'authentik.stages.authenticator_static', 'authentik.stages.authenticator_totp', 'authentik.stages.authenticator_validate', 'authentik.stages.authenticator_webauthn', 'authentik.stages.captcha', 'authentik.stages.consent', 'authentik.stages.deny', 'authentik.stages.dummy', 'authentik.stages.email', 'authentik.stages.identification', 'authentik.stages.invitation', 'authentik.stages.password', 'authentik.stages.prompt', 'authentik.stages.redirect', 'authentik.stages.user_delete', 'authentik.stages.user_login', 'authentik.stages.user_logout', 'authentik.stages.user_write', 'authentik.tasks.schedules', 'authentik.brands', 'authentik.blueprints', 'guardian', 'authentik.enterprise.audit', 'authentik.enterprise.endpoints.connectors.agent', 'authentik.enterprise.endpoints.connectors.fleet', 'authentik.enterprise.endpoints.connectors.google_chrome', 'authentik.enterprise.lifecycle', 'authentik.enterprise.policies.unique_password', 'authentik.enterprise.providers.google_workspace', 'authentik.enterprise.providers.microsoft_entra', 'authentik.enterprise.providers.radius', 'authentik.enterprise.providers.scim', 'authentik.enterprise.providers.ssf', 'authentik.enterprise.providers.ws_federation', 'authentik.enterprise.reports', 'authentik.enterprise.stages.account_lockdown', 'authentik.enterprise.stages.authenticator_endpoint_gdtc', 'authentik.enterprise.stages.mtls', 'authentik.enterprise.stages.source']
TENANT_MODEL = 'authentik_tenants.Tenant'
TENANT_DOMAIN_MODEL = 'authentik_tenants.Domain'
TENANT_CREATION_FAKES_MIGRATIONS = True
TENANT_BASE_SCHEMA = 'template'
PUBLIC_SCHEMA_NAME = 'public'
GUARDIAN_GROUP_MODEL = 'authentik_core.Group'
GUARDIAN_ROLE_MODEL = 'authentik_rbac.Role'
SPECTACULAR_SETTINGS = {'TITLE': 'authentik', 'DESCRIPTION': 'Making authentication simple.', 'VERSION': '2026.8.0-rc1', 'COMPONENT_SPLIT_REQUEST': True, 'SCHEMA_PATH_PREFIX': '/api/v([0-9]+(beta)?)', 'SCHEMA_PATH_PREFIX_TRIM': True, 'SERVERS': [{'url': '/api/v3'}], 'CONTACT': {'email': 'hello@goauthentik.io'}, 'AUTHENTICATION_WHITELIST': ['authentik.api.authentication.TokenAuthentication'], 'LICENSE': {'name': 'MIT', 'url': 'https://github.com/goauthentik/authentik/blob/main/LICENSE'}, 'ENUM_NAME_OVERRIDES': {'AppEnum': 'authentik.lib.api.Apps', 'AuthenticationEnum': 'authentik.flows.models.FlowAuthenticationRequirement', 'ConsentModeEnum': 'authentik.stages.consent.models.ConsentMode', 'CountryCodeEnum': 'django_countries.countries', 'DeviceClassesEnum': 'authentik.stages.authenticator_validate.models.DeviceClasses', 'DeviceFactsOSFamily': 'authentik.endpoints.facts.OSFamily', 'EventActions': 'authentik.events.models.EventAction', 'FlowDesignationEnum': 'authentik.flows.models.FlowDesignation', 'FlowLayoutEnum': 'authentik.flows.models.FlowLayout', 'LDAPAPIAccessMode': 'authentik.providers.ldap.models.APIAccessMode', 'ModelEnum': 'authentik.lib.api.Models', 'OutgoingSyncDeleteAction': 'authentik.lib.sync.outgoing.models.OutgoingSyncDeleteAction', 'PKCEMethodEnum': 'authentik.sources.oauth.models.PKCEMethod', 'PolicyEngineMode': 'authentik.policies.models.PolicyEngineMode', 'PromptTypeEnum': 'authentik.stages.prompt.models.FieldTypes', 'ProxyMode': 'authentik.providers.proxy.models.ProxyMode', 'RedirectURITypeEnum': 'authentik.providers.oauth2.models.RedirectURIType', 'SAMLBindingsEnum': 'authentik.providers.saml.models.SAMLBindings', 'SAMLLogoutMethods': 'authentik.providers.saml.models.SAMLLogoutMethods', 'SAMLNameIDPolicyEnum': 'authentik.sources.saml.models.SAMLNameIDPolicy', 'SCIMAuthenticationModeEnum': 'authentik.providers.scim.models.SCIMAuthenticationMode', 'StageModeEnum': 'authentik.endpoints.models.StageMode', 'TaskAggregatedStatusEnum': 'authentik.tasks.models.TaskStatus', 'TaskStatusEnum': 'django_dramatiq_postgres.models.TaskState', 'TransportModeEnum': 'authentik.events.models.TransportMode', 'UserTypeEnum': 'authentik.core.models.UserTypes', 'UserVerificationEnum': 'authentik.stages.authenticator_webauthn.models.UserVerification', 'WebAuthnHintEnum': 'authentik.stages.authenticator_webauthn.models.WebAuthnHint'}, 'ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE': False, 'ENUM_GENERATE_CHOICE_DESCRIPTION': False, 'PREPROCESSING_HOOKS': ['authentik.api.v3.schema.cleanup.preprocess_schema_exclude_non_api'], 'POSTPROCESSING_HOOKS': ['authentik.api.v3.schema.response.postprocess_schema_register', 'authentik.api.v3.schema.response.postprocess_schema_responses', 'authentik.api.v3.schema.query.postprocess_schema_query_params', 'authentik.api.v3.schema.cleanup.postprocess_schema_remove_unused', 'authentik.api.v3.schema.search.postprocess_schema_search_autocomplete', 'authentik.api.v3.schema.enum.postprocess_schema_enums']}
REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'authentik.api.pagination.Pagination', 'DEFAULT_FILTER_BACKENDS': ['authentik.api.search.ql.QLSearch', 'authentik.rbac.filters.ObjectFilter', 'django_filters.rest_framework.DjangoFilterBackend', 'authentik.api.ordering.NullsAwareOrderingFilter'], 'DEFAULT_PERMISSION_CLASSES': ('authentik.rbac.permissions.ObjectPermissions',), 'DEFAULT_AUTHENTICATION_CLASSES': ('authentik.api.authentication.TokenAuthentication', 'rest_framework.authentication.SessionAuthentication'), 'DEFAULT_RENDERER_CLASSES': ['drf_orjson_renderer.renderers.ORJSONRenderer'], 'ORJSON_RENDERER_OPTIONS': [4, 128], 'DEFAULT_PARSER_CLASSES': ['drf_orjson_renderer.parsers.ORJSONParser'], 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', 'TEST_REQUEST_DEFAULT_FORMAT': 'json', 'DEFAULT_THROTTLE_CLASSES': ['rest_framework.throttling.AnonRateThrottle'], 'DEFAULT_THROTTLE_RATES': {'anon': '1000/second'}}
CACHES = {'default': {'BACKEND': 'django_postgres_cache.backend.DatabaseCache', 'KEY_FUNCTION': 'django_tenants.cache.make_key', 'REVERSE_KEY_FUNCTION': 'django_tenants.cache.reverse_key'}}
SESSION_ENGINE = 'authentik.core.sessions'
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
MIDDLEWARE_FIRST = ['django_prometheus.middleware.PrometheusBeforeMiddleware']
MIDDLEWARE = ['django_prometheus.middleware.PrometheusBeforeMiddleware', 'authentik.tenants.middleware.DefaultTenantMiddleware', 'authentik.root.middleware.LoggingMiddleware', 'authentik.root.middleware.ClientIPMiddleware', 'authentik.stages.user_login.middleware.BoundSessionMiddleware', 'django.middleware.locale.LocaleMiddleware', 'authentik.core.middleware.AuthenticationMiddleware', 'authentik.core.middleware.RequestIDMiddleware', 'authentik.brands.middleware.BrandMiddleware', 'authentik.events.middleware.AuditMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.middleware.common.CommonMiddleware', 'authentik.root.middleware.CsrfViewMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'authentik.core.middleware.ImpersonateMiddleware', 'authentik.rbac.middleware.InitialPermissionsMiddleware', 'authentik.enterprise.middleware.EnterpriseMiddleware', 'django_prometheus.middleware.PrometheusAfterMiddleware']
MIDDLEWARE_LAST = ['django_prometheus.middleware.PrometheusAfterMiddleware']
ROOT_URLCONF = 'authentik.root.urls'
TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': ['/templates'], 'APP_DIRS': True, 'OPTIONS': {'context_processors': ['django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'authentik.brands.utils.context_processor']}}]
ASGI_APPLICATION = 'authentik.root.asgi.application'
ORIGINAL_BACKEND = 'django_prometheus.db.backends.postgresql'
POSTGRES_EXTRA_DB_BACKEND_BASE = 'authentik.root.db'
DATABASES = {'default': {'ENGINE': 'psqlextra.backend', 'HOST': 'localhost', 'NAME': 'authentik', 'USER': 'authentik', 'PASSWORD': 'EK-5jnKfjrGRm<77', 'PORT': 5432, 'OPTIONS': {'sslmode': 'disable', 'sslrootcert': None, 'sslcert': None, 'sslkey': None, 'pool': False}, 'CONN_MAX_AGE': 0, 'CONN_HEALTH_CHECKS': False, 'DISABLE_SERVER_SIDE_CURSORS': False, 'TEST': {'NAME': 'test_authentik', 'CHARSET': None, 'COLLATION': None, 'MIGRATE': True, 'MIRROR': None}, 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'TIME_ZONE': None, 'SCHEMA': 'public'}}
DATABASE_ROUTERS = ('authentik.tenants.db.FailoverRouter', 'django_tenants.routers.TenantSyncRouter')
POSTGRES_EXTRA_AUTO_EXTENSION_SET_UP = False
CHANNEL_LAYERS = {'default': {'BACKEND': 'django_channels_postgres.layer.PostgresChannelLayer'}}
EMAIL_HOST = 'localhost'
EMAIL_PORT = 25
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_USE_TLS = False
EMAIL_USE_SSL = False
EMAIL_TIMEOUT = 10
DEFAULT_FROM_EMAIL = 'authentik@localhost'
SERVER_EMAIL = 'authentik@localhost'
EMAIL_SUBJECT_PREFIX = '[authentik] '
AUTH_PASSWORD_VALIDATORS = [{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'}, {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'}, {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'}, {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}]
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
LOCALE_PATHS = ['./locale']
TEST = False
DRAMATIQ = {'broker_class': 'authentik.tasks.broker.Broker', 'channel_prefix': 'authentik', 'task_model': 'authentik.tasks.models.Task', 'task_purge_interval': 86400.0, 'task_expiration': 2592000.0, 'autodiscovery': {'enabled': True, 'setup_module': 'authentik.tasks.setup', 'apps_prefix': 'authentik'}, 'worker': {'processes': 1, 'threads': 2, 'consumer_listen_timeout': 30.0, 'watch_folder': PosixPath('/home/runner/work/authentik/authentik/authentik')}, 'scheduler_class': 'authentik.tasks.schedules.scheduler.Scheduler', 'schedule_model': 'authentik.tasks.schedules.models.Schedule', 'scheduler_interval': 60.0, 'middlewares': (('django_dramatiq_postgres.middleware.FullyQualifiedActorName', {}), ('django_dramatiq_postgres.middleware.DbConnectionMiddleware', {}), ('django_dramatiq_postgres.middleware.TaskStateBeforeMiddleware', {}), ('dramatiq.middleware.age_limit.AgeLimit', {}), ('dramatiq.middleware.time_limit.TimeLimit', {'time_limit': 600000.0}), ('dramatiq.middleware.shutdown.ShutdownNotifications', {}), ('dramatiq.middleware.callbacks.Callbacks', {}), ('dramatiq.middleware.pipelines.Pipelines', {}), ('dramatiq.middleware.retries.Retries', {'max_retries': 5, 'max_backoff': 3600000}), ('dramatiq.results.middleware.Results', {'store_results': True, 'backend': <django_dramatiq_postgres.results.PostgresBackend object>}), ('authentik.tasks.middleware.StartupSignalsMiddleware', {}), ('authentik.tasks.middleware.CurrentTask', {}), ('authentik.tasks.middleware.TenantMiddleware', {}), ('authentik.tasks.middleware.ModelDataMiddleware', {}), ('authentik.tasks.middleware.TaskLogMiddleware', {}), ('authentik.tasks.middleware.LoggingMiddleware', {}), ('authentik.tasks.middleware.DescriptionMiddleware', {}), ('authentik.tasks.middleware.MetricsMiddleware', {'prefix': 'authentik'}), ('django_dramatiq_postgres.middleware.TaskStateAfterMiddleware', {})), 'test': False}
env = 'ci'
STATICFILES_DIRS = [PosixPath('/home/runner/work/authentik/authentik/web')]
STATIC_URL = '/static/'
STORAGES = {'staticfiles': {'BACKEND': 'django.contrib.staticfiles.storage.StaticFilesStorage'}}
LOGGING = {'version': 1, 'disable_existing_loggers': False, 'formatters': {'json': {'()': <class 'structlog.stdlib.ProcessorFormatter'>, 'processor': <structlog.processors.JSONRenderer object>, 'foreign_pre_chain': [<function add_log_level>, <function add_logger_name>, <structlog.processors.TimeStamper object>, <structlog.processors.StackInfoRenderer object>, <structlog.processors.ExceptionRenderer object>]}, 'console': {'()': <class 'structlog.stdlib.ProcessorFormatter'>, 'processor': <structlog.dev.ConsoleRenderer object>, 'foreign_pre_chain': [<function add_log_level>, <function add_logger_name>, <structlog.processors.TimeStamper object>, <structlog.processors.StackInfoRenderer object>]}}, 'handlers': {'console': {'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'json'}}, 'loggers': {'': {'handlers': ['console'], 'level': 'DEBUG', 'propagate': False}, 'authentik': {'handlers': ['console'], 'level': 'DEBUG', 'propagate': False}, 'django': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'django.request': {'handlers': ['console'], 'level': 'ERROR', 'propagate': False}, 'selenium': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'docker': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'urllib3': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'websockets': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'daphne': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'kubernetes': {'handlers': ['console'], 'level': 'INFO', 'propagate': False}, 'asyncio': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'fsevents': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'uvicorn': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'gunicorn': {'handlers': ['console'], 'level': 'INFO', 'propagate': False}, 'requests_mock': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'hpack': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'httpx': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'azure': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}, 'httpcore': {'handlers': ['console'], 'level': 'WARNING', 'propagate': False}}}
SILENCED_SYSTEM_CHECKS = ['security.W003', 'security.W010', 'security.W004', 'security.W008']
def subtract_list(a: list, b: list) -> list:
520def subtract_list(a: list, b: list) -> list:
521    return [item for item in a if item not in b]
INSTALLED_APPS = ['authentik.commands', 'django_tenants', 'authentik.tenants', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.humanize', 'django.contrib.postgres', 'psqlextra', 'rest_framework', 'django_filters', 'drf_spectacular', 'django_prometheus', 'django_countries', 'pgactivity', 'pglock', 'channels', 'django_channels_postgres', 'django_dramatiq_postgres', 'authentik.tasks', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'pgtrigger', 'django_postgres_cache', 'authentik.admin', 'authentik.api', 'authentik.core', 'authentik.crypto', 'authentik.endpoints', 'authentik.endpoints.connectors.agent', 'authentik.enterprise', 'authentik.events', 'authentik.admin.files', 'authentik.flows', 'authentik.outposts', 'authentik.policies.dummy', 'authentik.policies.event_matcher', 'authentik.policies.expiry', 'authentik.policies.expression', 'authentik.policies.geoip', 'authentik.policies.password', 'authentik.policies.reputation', 'authentik.policies', 'authentik.providers.ldap', 'authentik.providers.oauth2', 'authentik.providers.proxy', 'authentik.providers.rac', 'authentik.providers.radius', 'authentik.providers.saml', 'authentik.providers.scim', 'authentik.rbac', 'authentik.recovery', 'authentik.sources.kerberos', 'authentik.sources.ldap', 'authentik.sources.oauth', 'authentik.sources.plex', 'authentik.sources.saml', 'authentik.sources.scim', 'authentik.sources.telegram', 'authentik.stages.authenticator', 'authentik.stages.authenticator_duo', 'authentik.stages.authenticator_email', 'authentik.stages.authenticator_sms', 'authentik.stages.authenticator_static', 'authentik.stages.authenticator_totp', 'authentik.stages.authenticator_validate', 'authentik.stages.authenticator_webauthn', 'authentik.stages.captcha', 'authentik.stages.consent', 'authentik.stages.deny', 'authentik.stages.dummy', 'authentik.stages.email', 'authentik.stages.identification', 'authentik.stages.invitation', 'authentik.stages.password', 'authentik.stages.prompt', 'authentik.stages.redirect', 'authentik.stages.user_delete', 'authentik.stages.user_login', 'authentik.stages.user_logout', 'authentik.stages.user_write', 'authentik.tasks.schedules', 'authentik.brands', 'authentik.blueprints', 'guardian', 'authentik.enterprise.audit', 'authentik.enterprise.endpoints.connectors.agent', 'authentik.enterprise.endpoints.connectors.fleet', 'authentik.enterprise.endpoints.connectors.google_chrome', 'authentik.enterprise.lifecycle', 'authentik.enterprise.policies.unique_password', 'authentik.enterprise.providers.google_workspace', 'authentik.enterprise.providers.microsoft_entra', 'authentik.enterprise.providers.radius', 'authentik.enterprise.providers.scim', 'authentik.enterprise.providers.ssf', 'authentik.enterprise.providers.ws_federation', 'authentik.enterprise.reports', 'authentik.enterprise.stages.account_lockdown', 'authentik.enterprise.stages.authenticator_endpoint_gdtc', 'authentik.enterprise.stages.mtls', 'authentik.enterprise.stages.source']