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 "ConsentModeEnum": "authentik.stages.consent.models.ConsentMode", 176 "CountryCodeEnum": "django_countries.countries", 177 "DeviceClassesEnum": "authentik.stages.authenticator_validate.models.DeviceClasses", 178 "DeviceFactsOSFamily": "authentik.endpoints.facts.OSFamily", 179 "EventActions": "authentik.events.models.EventAction", 180 "FlowDesignationEnum": "authentik.flows.models.FlowDesignation", 181 "FlowLayoutEnum": "authentik.flows.models.FlowLayout", 182 "LDAPAPIAccessMode": "authentik.providers.ldap.models.APIAccessMode", 183 "ModelEnum": "authentik.lib.api.Models", 184 "OutgoingSyncDeleteAction": "authentik.lib.sync.outgoing.models.OutgoingSyncDeleteAction", 185 "PKCEMethodEnum": "authentik.sources.oauth.models.PKCEMethod", 186 "PolicyEngineMode": "authentik.policies.models.PolicyEngineMode", 187 "PromptTypeEnum": "authentik.stages.prompt.models.FieldTypes", 188 "ProxyMode": "authentik.providers.proxy.models.ProxyMode", 189 "SAMLBindingsEnum": "authentik.providers.saml.models.SAMLBindings", 190 "SAMLLogoutMethods": "authentik.providers.saml.models.SAMLLogoutMethods", 191 "SAMLNameIDPolicyEnum": "authentik.sources.saml.models.SAMLNameIDPolicy", 192 "SCIMAuthenticationModeEnum": "authentik.providers.scim.models.SCIMAuthenticationMode", 193 "StageModeEnum": "authentik.endpoints.models.StageMode", 194 "TaskAggregatedStatusEnum": "authentik.tasks.models.TaskStatus", 195 "TaskStatusEnum": "django_dramatiq_postgres.models.TaskState", 196 "TransportModeEnum": "authentik.events.models.TransportMode", 197 "UserTypeEnum": "authentik.core.models.UserTypes", 198 "UserVerificationEnum": "authentik.stages.authenticator_webauthn.models.UserVerification", 199 "WebAuthnHintEnum": "authentik.stages.authenticator_webauthn.models.WebAuthnHint", 200 }, 201 "ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE": False, 202 "ENUM_GENERATE_CHOICE_DESCRIPTION": False, 203 "PREPROCESSING_HOOKS": [ 204 "authentik.api.v3.schema.cleanup.preprocess_schema_exclude_non_api", 205 ], 206 "POSTPROCESSING_HOOKS": [ 207 "authentik.api.v3.schema.response.postprocess_schema_register", 208 "authentik.api.v3.schema.response.postprocess_schema_responses", 209 "authentik.api.v3.schema.query.postprocess_schema_query_params", 210 "authentik.api.v3.schema.cleanup.postprocess_schema_remove_unused", 211 "authentik.api.v3.schema.enum.postprocess_schema_enums", 212 ], 213} 214 215REST_FRAMEWORK = { 216 "DEFAULT_PAGINATION_CLASS": "authentik.api.pagination.Pagination", 217 "DEFAULT_FILTER_BACKENDS": [ 218 "authentik.rbac.filters.ObjectFilter", 219 "django_filters.rest_framework.DjangoFilterBackend", 220 "rest_framework.filters.OrderingFilter", 221 "rest_framework.filters.SearchFilter", 222 ], 223 "DEFAULT_PERMISSION_CLASSES": ("authentik.rbac.permissions.ObjectPermissions",), 224 "DEFAULT_AUTHENTICATION_CLASSES": ( 225 "authentik.api.authentication.TokenAuthentication", 226 "rest_framework.authentication.SessionAuthentication", 227 ), 228 "DEFAULT_RENDERER_CLASSES": [ 229 "drf_orjson_renderer.renderers.ORJSONRenderer", 230 ], 231 "ORJSON_RENDERER_OPTIONS": [ 232 orjson.OPT_NON_STR_KEYS, 233 orjson.OPT_UTC_Z, 234 ], 235 "DEFAULT_PARSER_CLASSES": [ 236 "drf_orjson_renderer.parsers.ORJSONParser", 237 ], 238 "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", 239 "TEST_REQUEST_DEFAULT_FORMAT": "json", 240 "DEFAULT_THROTTLE_CLASSES": ["rest_framework.throttling.AnonRateThrottle"], 241 "DEFAULT_THROTTLE_RATES": { 242 "anon": CONFIG.get("throttle.default"), 243 }, 244} 245 246 247CACHES = { 248 "default": { 249 "BACKEND": "django_postgres_cache.backend.DatabaseCache", 250 "KEY_FUNCTION": "django_tenants.cache.make_key", 251 "REVERSE_KEY_FUNCTION": "django_tenants.cache.reverse_key", 252 } 253} 254SESSION_ENGINE = "authentik.core.sessions" 255# Configured via custom SessionMiddleware 256# SESSION_COOKIE_SAMESITE = "None" 257# SESSION_COOKIE_SECURE = True 258SESSION_COOKIE_AGE = timedelta_from_string( 259 CONFIG.get("sessions.unauthenticated_age", "days=1") 260).total_seconds() 261SESSION_EXPIRE_AT_BROWSER_CLOSE = True 262 263MESSAGE_STORAGE = "authentik.root.ws.storage.ChannelsStorage" 264 265MIDDLEWARE_FIRST = [ 266 "django_prometheus.middleware.PrometheusBeforeMiddleware", 267] 268MIDDLEWARE = [ 269 "authentik.tenants.middleware.DefaultTenantMiddleware", 270 "authentik.root.middleware.LoggingMiddleware", 271 "authentik.root.middleware.ClientIPMiddleware", 272 "authentik.stages.user_login.middleware.BoundSessionMiddleware", 273 "django.middleware.locale.LocaleMiddleware", 274 "authentik.core.middleware.AuthenticationMiddleware", 275 "authentik.core.middleware.RequestIDMiddleware", 276 "authentik.brands.middleware.BrandMiddleware", 277 "authentik.events.middleware.AuditMiddleware", 278 "django.middleware.security.SecurityMiddleware", 279 "django.middleware.common.CommonMiddleware", 280 "authentik.root.middleware.CsrfViewMiddleware", 281 "django.contrib.messages.middleware.MessageMiddleware", 282 "django.middleware.clickjacking.XFrameOptionsMiddleware", 283 "authentik.core.middleware.ImpersonateMiddleware", 284 "authentik.rbac.middleware.InitialPermissionsMiddleware", 285] 286MIDDLEWARE_LAST = [ 287 "django_prometheus.middleware.PrometheusAfterMiddleware", 288] 289 290ROOT_URLCONF = "authentik.root.urls" 291 292TEMPLATES = [ 293 { 294 "BACKEND": "django.template.backends.django.DjangoTemplates", 295 "DIRS": [CONFIG.get("email.template_dir")], 296 "APP_DIRS": True, 297 "OPTIONS": { 298 "context_processors": [ 299 "django.template.context_processors.debug", 300 "django.template.context_processors.request", 301 "django.contrib.auth.context_processors.auth", 302 "django.contrib.messages.context_processors.messages", 303 "authentik.brands.utils.context_processor", 304 ], 305 }, 306 }, 307] 308 309ASGI_APPLICATION = "authentik.root.asgi.application" 310 311 312# Database 313# https://docs.djangoproject.com/en/2.1/ref/settings/#databases 314 315# Custom overrides for database backends 316# The tree looks like this: 317# psqlextra backend 318# -> authentik custom backend 319# -> django_tenants backend 320# -> django_prometheus backend 321# -> django built-in backend 322ORIGINAL_BACKEND = "django_prometheus.db.backends.postgresql" 323POSTGRES_EXTRA_DB_BACKEND_BASE = "authentik.root.db" 324DATABASES = django_db_config() 325 326DATABASE_ROUTERS = ( 327 "authentik.tenants.db.FailoverRouter", 328 "django_tenants.routers.TenantSyncRouter", 329) 330 331# We don't use HStore 332POSTGRES_EXTRA_AUTO_EXTENSION_SET_UP = False 333 334CHANNEL_LAYERS = { 335 "default": { 336 "BACKEND": "django_channels_postgres.layer.PostgresChannelLayer", 337 }, 338} 339 340# Email 341# These values should never actually be used, emails are only sent from email stages, which 342# loads the config directly from CONFIG 343# See authentik/stages/email/models.py, line 105 344EMAIL_HOST = CONFIG.get("email.host") 345EMAIL_PORT = CONFIG.get_int("email.port") 346EMAIL_HOST_USER = CONFIG.get("email.username") 347EMAIL_HOST_PASSWORD = CONFIG.get("email.password") 348EMAIL_USE_TLS = CONFIG.get_bool("email.use_tls", False) 349EMAIL_USE_SSL = CONFIG.get_bool("email.use_ssl", False) 350EMAIL_TIMEOUT = CONFIG.get_int("email.timeout") 351DEFAULT_FROM_EMAIL = CONFIG.get("email.from") 352SERVER_EMAIL = DEFAULT_FROM_EMAIL 353EMAIL_SUBJECT_PREFIX = "[authentik] " 354 355# Password validation 356# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators 357 358AUTH_PASSWORD_VALIDATORS = [ 359 { 360 "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", 361 }, 362 {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, 363 {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, 364 {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, 365] 366 367 368# Internationalization 369# https://docs.djangoproject.com/en/2.1/topics/i18n/ 370 371LANGUAGE_CODE = "en-us" 372 373TIME_ZONE = "UTC" 374 375USE_I18N = True 376 377USE_TZ = True 378 379LOCALE_PATHS = ["./locale"] 380 381 382# Tests 383 384TEST = False 385TEST_RUNNER = "authentik.root.test_runner.PytestTestRunner" 386 387 388# Dramatiq 389 390DRAMATIQ = { 391 "broker_class": "authentik.tasks.broker.Broker", 392 "channel_prefix": "authentik", 393 "task_model": "authentik.tasks.models.Task", 394 "task_purge_interval": timedelta_from_string( 395 CONFIG.get("worker.task_purge_interval") 396 ).total_seconds(), 397 "task_expiration": timedelta_from_string(CONFIG.get("worker.task_expiration")).total_seconds(), 398 "autodiscovery": { 399 "enabled": True, 400 "setup_module": "authentik.tasks.setup", 401 "apps_prefix": "authentik", 402 }, 403 "worker": { 404 "processes": CONFIG.get_int("worker.processes", 2), 405 "threads": CONFIG.get_int("worker.threads", 1), 406 "consumer_listen_timeout": timedelta_from_string( 407 CONFIG.get("worker.consumer_listen_timeout") 408 ).total_seconds(), 409 "watch_folder": BASE_DIR / "authentik", 410 }, 411 "scheduler_class": "authentik.tasks.schedules.scheduler.Scheduler", 412 "schedule_model": "authentik.tasks.schedules.models.Schedule", 413 "scheduler_interval": timedelta_from_string( 414 CONFIG.get("worker.scheduler_interval") 415 ).total_seconds(), 416 "middlewares": ( 417 ("django_dramatiq_postgres.middleware.FullyQualifiedActorName", {}), 418 ("django_dramatiq_postgres.middleware.DbConnectionMiddleware", {}), 419 ("django_dramatiq_postgres.middleware.TaskStateBeforeMiddleware", {}), 420 ("dramatiq.middleware.age_limit.AgeLimit", {}), 421 ( 422 "dramatiq.middleware.time_limit.TimeLimit", 423 { 424 "time_limit": timedelta_from_string( 425 CONFIG.get("worker.task_default_time_limit") 426 ).total_seconds() 427 * 1000 428 }, 429 ), 430 ("dramatiq.middleware.shutdown.ShutdownNotifications", {}), 431 ("dramatiq.middleware.callbacks.Callbacks", {}), 432 ("dramatiq.middleware.pipelines.Pipelines", {}), 433 ( 434 "dramatiq.middleware.retries.Retries", 435 { 436 "max_retries": CONFIG.get_int("worker.task_max_retries") if not TEST else 0, 437 "max_backoff": 60 * 60 * 1000, # 1 hour 438 }, 439 ), 440 ("dramatiq.results.middleware.Results", {"store_results": True}), 441 ("authentik.tasks.middleware.StartupSignalsMiddleware", {}), 442 ("authentik.tasks.middleware.CurrentTask", {}), 443 ("authentik.tasks.middleware.TenantMiddleware", {}), 444 ("authentik.tasks.middleware.ModelDataMiddleware", {}), 445 ("authentik.tasks.middleware.TaskLogMiddleware", {}), 446 ("authentik.tasks.middleware.LoggingMiddleware", {}), 447 ("authentik.tasks.middleware.DescriptionMiddleware", {}), 448 ("authentik.tasks.middleware.WorkerHealthcheckMiddleware", {}), 449 ("authentik.tasks.middleware.WorkerStatusMiddleware", {}), 450 ( 451 "authentik.tasks.middleware.MetricsMiddleware", 452 { 453 "prefix": "authentik", 454 }, 455 ), 456 ("django_dramatiq_postgres.middleware.TaskStateAfterMiddleware", {}), 457 ), 458 "test": TEST, 459} 460 461 462# Sentry integration 463 464env = get_env() 465_ERROR_REPORTING = CONFIG.get_bool("error_reporting.enabled", False) 466if _ERROR_REPORTING: 467 sentry_env = CONFIG.get("error_reporting.environment", "customer") 468 sentry_init(spotlight=DEBUG) 469 set_tag("authentik.uuid", sha512(str(SECRET_KEY).encode("ascii")).hexdigest()[:16]) 470 471 472# Static files (CSS, JavaScript, Images) 473# https://docs.djangoproject.com/en/2.1/howto/static-files/ 474 475STATICFILES_DIRS = [BASE_DIR / Path("web")] 476STATIC_URL = CONFIG.get("web.path", "/") + "static/" 477 478STORAGES = { 479 "staticfiles": { 480 "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage", 481 }, 482} 483 484# Django 5.2.8 and CVE-2025-64458 added a strong enforcement of 2048 characters 485# as the maximum for a URL to redirect to, mostly for running on Windows. 486# However, our URLs can easily exceed that with OAuth/SAML Query parameters or hash values. 487# 8192 should cover most cases. 488utils_http.MAX_URL_LENGTH = utils_http.MAX_URL_LENGTH * 4 489 490structlog_configure() 491LOGGING = get_logger_config() 492 493 494_DISALLOWED_ITEMS = [ 495 "SHARED_APPS", 496 "TENANT_APPS", 497 "INSTALLED_APPS", 498 "MIDDLEWARE_FIRST", 499 "MIDDLEWARE", 500 "MIDDLEWARE_LAST", 501 "AUTHENTICATION_BACKENDS", 502 "SPECTACULAR_SETTINGS", 503 "REST_FRAMEWORK", 504] 505 506SILENCED_SYSTEM_CHECKS = [ 507 # We use our own subclass of django.middleware.csrf.CsrfViewMiddleware 508 "security.W003", 509 # We don't set SESSION_COOKIE_SECURE since we use a custom SessionMiddleware subclass 510 "security.W010", 511 # HSTS: This is configured in reverse proxies/the go proxy, not in django 512 "security.W004", 513 # https redirect: This is configured in reverse proxies/the go proxy, not in django 514 "security.W008", 515] 516 517 518def subtract_list(a: list, b: list) -> list: 519 return [item for item in a if item not in b] 520 521 522def _filter_and_update(apps: list[str]) -> None: 523 for _app in set(apps): 524 if not _app.startswith("authentik"): 525 continue 526 _update_settings(f"{_app}.settings") 527 528 529def _update_settings(app_path: str) -> None: 530 try: 531 settings_module = importlib.import_module(app_path) 532 CONFIG.log("debug", "Loaded app settings", path=app_path) 533 534 new_shared_apps = subtract_list(getattr(settings_module, "SHARED_APPS", []), SHARED_APPS) 535 new_tenant_apps = subtract_list(getattr(settings_module, "TENANT_APPS", []), TENANT_APPS) 536 SHARED_APPS.extend(new_shared_apps) 537 TENANT_APPS.extend(new_tenant_apps) 538 _filter_and_update(new_shared_apps + new_tenant_apps) 539 540 MIDDLEWARE_FIRST.extend(getattr(settings_module, "MIDDLEWARE_FIRST", [])) 541 MIDDLEWARE.extend(getattr(settings_module, "MIDDLEWARE", [])) 542 543 AUTHENTICATION_BACKENDS.extend(getattr(settings_module, "AUTHENTICATION_BACKENDS", [])) 544 SPECTACULAR_SETTINGS.update(getattr(settings_module, "SPECTACULAR_SETTINGS", {})) 545 REST_FRAMEWORK.update(getattr(settings_module, "REST_FRAMEWORK", {})) 546 547 for _attr in dir(settings_module): 548 if not _attr.startswith("__") and _attr not in _DISALLOWED_ITEMS: 549 globals()[_attr] = getattr(settings_module, _attr) 550 except ImportError: 551 pass 552 553 554# Attempt to load enterprise app, if available 555try: 556 importlib.import_module("authentik.enterprise.apps") 557 CONFIG.log("info", "Enabled authentik enterprise") 558 TENANT_APPS.insert(TENANT_APPS.index("authentik.events"), "authentik.enterprise") 559except ImportError: 560 pass 561 562 563if DEBUG: 564 REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"].append( 565 "rest_framework.renderers.BrowsableAPIRenderer" 566 ) 567 SHARED_APPS.insert(SHARED_APPS.index("django.contrib.staticfiles"), "daphne") 568 enable_debug_trace(True) 569 570 571CONFIG.log("info", "Booting authentik", version=authentik_version()) 572 573# Load subapps's settings 574_filter_and_update(SHARED_APPS + TENANT_APPS) 575_update_settings("data.user_settings") 576 577MIDDLEWARE = list(OrderedDict.fromkeys(MIDDLEWARE_FIRST + MIDDLEWARE + MIDDLEWARE_LAST)) 578SHARED_APPS = list(OrderedDict.fromkeys(SHARED_APPS + TENANT_APPS)) 579INSTALLED_APPS = list(OrderedDict.fromkeys(SHARED_APPS + TENANT_APPS))
BASE_DIR =
PosixPath('/home/runner/work/authentik/authentik')
DEBUG =
False
SECRET_KEY =
'bHyobnU2BszZqeFjdpSDwcx1dPSIQ0LyFuRF1YZF'
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_COOKIE_NAME =
'authentik_csrf'
CSRF_HEADER_NAME =
'HTTP_X_AUTHENTIK_CSRF'
LANGUAGE_COOKIE_NAME =
'authentik_language'
SESSION_COOKIE_NAME =
'authentik_session'
SESSION_COOKIE_DOMAIN =
None
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.search', '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.search', '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.5.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', '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', '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.enterprise.search.schema.postprocess_schema_search_autocomplete', 'authentik.api.v3.schema.enum.postprocess_schema_enums']}
REST_FRAMEWORK =
{'DEFAULT_PAGINATION_CLASS': 'authentik.enterprise.search.pagination.AutocompletePagination', 'DEFAULT_FILTER_BACKENDS': ['authentik.enterprise.search.ql.QLSearch', 'authentik.rbac.filters.ObjectFilter', 'django_filters.rest_framework.DjangoFilterBackend', 'rest_framework.filters.OrderingFilter'], '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_COOKIE_AGE =
86400.0
SESSION_EXPIRE_AT_BROWSER_CLOSE =
True
MESSAGE_STORAGE =
'authentik.root.ws.storage.ChannelsStorage'
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
TEST_RUNNER =
'authentik.root.test_runner.PytestTestRunner'
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}), ('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.WorkerHealthcheckMiddleware', {}), ('authentik.tasks.middleware.WorkerStatusMiddleware', {}), ('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:
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.search', 'authentik.enterprise.stages.authenticator_endpoint_gdtc', 'authentik.enterprise.stages.mtls', 'authentik.enterprise.stages.source']