Compare commits

..

6 Commits

Author SHA1 Message Date
e5c8229a83 tweaks 2025-06-27 12:57:27 -05:00
390f4d87da Optimised images with calibre/image-actions 2025-06-26 12:34:35 +00:00
9900312b5d fix image link 2025-06-26 07:11:58 -05:00
5a69ded74d major surgery 2025-06-24 10:52:03 -05:00
fbc7dbb151 more content 2025-06-23 18:53:49 -05:00
4e2e678de3 tweak 2025-06-20 17:34:21 -05:00
28 changed files with 469 additions and 374 deletions

View File

@ -11,6 +11,7 @@ from authentik.core.expression.exceptions import SkipObjectException
from authentik.core.models import User
from authentik.events.models import Event, EventAction
from authentik.lib.expression.evaluator import BaseEvaluator
from authentik.lib.utils.errors import exception_to_string
from authentik.policies.types import PolicyRequest
PROPERTY_MAPPING_TIME = Histogram(
@ -68,11 +69,12 @@ class PropertyMappingEvaluator(BaseEvaluator):
# For dry-run requests we don't save exceptions
if self.dry_run:
return
error_string = exception_to_string(exc)
event = Event.new(
EventAction.PROPERTY_MAPPING_EXCEPTION,
expression=expression_source,
message="Failed to execute property mapping",
).with_exception(exc)
message=error_string,
)
if "request" in self._context:
req: PolicyRequest = self._context["request"]
if req.http_request:

View File

@ -20,7 +20,7 @@ from authentik.core.models import Group, User
from authentik.events.models import Event, EventAction, Notification
from authentik.events.utils import model_to_dict
from authentik.lib.sentry import before_send
from authentik.lib.utils.errors import exception_to_dict
from authentik.lib.utils.errors import exception_to_string
from authentik.stages.authenticator_static.models import StaticToken
IGNORED_MODELS = tuple(
@ -170,16 +170,14 @@ class AuditMiddleware:
thread = EventNewThread(
EventAction.SUSPICIOUS_REQUEST,
request,
message=str(exception),
exception=exception_to_dict(exception),
message=exception_to_string(exception),
)
thread.run()
elif before_send({}, {"exc_info": (None, exception, None)}) is not None:
thread = EventNewThread(
EventAction.SYSTEM_EXCEPTION,
request,
message=str(exception),
exception=exception_to_dict(exception),
message=exception_to_string(exception),
)
thread.run()

View File

@ -38,7 +38,6 @@ from authentik.events.utils import (
)
from authentik.lib.models import DomainlessURLValidator, SerializerModel
from authentik.lib.sentry import SentryIgnoredException
from authentik.lib.utils.errors import exception_to_dict
from authentik.lib.utils.http import get_http_session
from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.models import PolicyBindingModel
@ -164,12 +163,6 @@ class Event(SerializerModel, ExpiringModel):
event = Event(action=action, app=app, context=cleaned_kwargs)
return event
def with_exception(self, exc: Exception) -> "Event":
"""Add data from 'exc' to the event in a database-saveable format"""
self.context.setdefault("message", str(exc))
self.context["exception"] = exception_to_dict(exc)
return self
def set_user(self, user: User) -> "Event":
"""Set `.user` based on user, ensuring the correct attributes are copied.
This should only be used when self.from_http is *not* used."""

View File

@ -127,8 +127,8 @@ class SystemTask(TenantTask):
)
Event.new(
EventAction.SYSTEM_TASK_EXCEPTION,
message=f"Task {self.__name__} encountered an error",
).with_exception(exc).save()
message=f"Task {self.__name__} encountered an error: {exception_to_string(exc)}",
).save()
def run(self, *args, **kwargs):
raise NotImplementedError

View File

@ -56,6 +56,7 @@ from authentik.flows.planner import (
)
from authentik.flows.stage import AccessDeniedStage, StageView
from authentik.lib.sentry import SentryIgnoredException
from authentik.lib.utils.errors import exception_to_string
from authentik.lib.utils.reflection import all_subclasses, class_to_path
from authentik.lib.utils.urls import is_url_absolute, redirect_with_qs
from authentik.policies.engine import PolicyEngine
@ -237,8 +238,8 @@ class FlowExecutorView(APIView):
self._logger.warning(exc)
Event.new(
action=EventAction.SYSTEM_EXCEPTION,
message="System exception during flow execution.",
).with_exception(exc).from_http(self.request)
message=exception_to_string(exc),
).from_http(self.request)
challenge = FlowErrorChallenge(self.request, exc)
challenge.is_valid(raise_exception=True)
return to_stage_response(self.request, HttpChallengeResponse(challenge))

View File

@ -14,6 +14,7 @@ from authentik.events.models import Event, EventAction
from authentik.lib.expression.exceptions import ControlFlowException
from authentik.lib.sync.mapper import PropertyMappingManager
from authentik.lib.sync.outgoing.exceptions import NotFoundSyncException, StopSync
from authentik.lib.utils.errors import exception_to_string
if TYPE_CHECKING:
from django.db.models import Model
@ -105,9 +106,9 @@ class BaseOutgoingSyncClient[
# Value error can be raised when assigning invalid data to an attribute
Event.new(
EventAction.CONFIGURATION_ERROR,
message="Failed to evaluate property-mapping",
message=f"Failed to evaluate property-mapping {exception_to_string(exc)}",
mapping=exc.mapping,
).with_exception(exc).save()
).save()
raise StopSync(exc, obj, exc.mapping) from exc
if not raw_final_object:
raise StopSync(ValueError("No mappings configured"), obj)

View File

@ -2,8 +2,6 @@
from traceback import extract_tb
from structlog.tracebacks import ExceptionDictTransformer
from authentik.lib.utils.reflection import class_to_path
TRACEBACK_HEADER = "Traceback (most recent call last):"
@ -19,8 +17,3 @@ def exception_to_string(exc: Exception) -> str:
f"{class_to_path(exc.__class__)}: {str(exc)}",
]
)
def exception_to_dict(exc: Exception) -> dict:
"""Format exception as a dictionary"""
return ExceptionDictTransformer()((type(exc), exc, exc.__traceback__))

View File

@ -35,6 +35,7 @@ from authentik.events.models import Event, EventAction
from authentik.lib.config import CONFIG
from authentik.lib.models import InheritanceForeignKey, SerializerModel
from authentik.lib.sentry import SentryIgnoredException
from authentik.lib.utils.errors import exception_to_string
from authentik.outposts.controllers.k8s.utils import get_namespace
OUR_VERSION = parse(__version__)
@ -325,8 +326,9 @@ class Outpost(SerializerModel, ManagedModel):
"While setting the permissions for the service-account, a "
"permission was not found: Check "
"https://goauthentik.io/docs/troubleshooting/missing_permission"
),
).with_exception(exc).set_user(user).save()
)
+ exception_to_string(exc),
).set_user(user).save()
else:
app_label, perm = model_or_perm.split(".")
permission = Permission.objects.filter(

View File

@ -10,7 +10,7 @@ from structlog.stdlib import get_logger
from authentik.events.models import Event, EventAction
from authentik.lib.config import CONFIG
from authentik.lib.utils.errors import exception_to_dict
from authentik.lib.utils.errors import exception_to_string
from authentik.lib.utils.reflection import class_to_path
from authentik.policies.apps import HIST_POLICIES_EXECUTION_TIME
from authentik.policies.exceptions import PolicyException
@ -95,13 +95,10 @@ class PolicyProcess(PROCESS_CLASS):
except PolicyException as exc:
# Either use passed original exception or whatever we have
src_exc = exc.src_exc if exc.src_exc else exc
error_string = exception_to_string(src_exc)
# Create policy exception event, only when we're not debugging
if not self.request.debug:
self.create_event(
EventAction.POLICY_EXCEPTION,
message="Policy failed to execute",
exception=exception_to_dict(src_exc),
)
self.create_event(EventAction.POLICY_EXCEPTION, message=error_string)
LOGGER.debug("P_ENG(proc): error, using failure result", exc=src_exc)
policy_result = PolicyResult(self.binding.failure_result, str(src_exc))
policy_result.source_binding = self.binding
@ -146,5 +143,5 @@ class PolicyProcess(PROCESS_CLASS):
try:
self.connection.send(self.profiling_wrapper())
except Exception as exc:
LOGGER.warning("Policy failed to run", exc=exc)
LOGGER.warning("Policy failed to run", exc=exception_to_string(exc))
self.connection.send(PolicyResult(False, str(exc)))

View File

@ -237,4 +237,4 @@ class TestPolicyProcess(TestCase):
self.assertEqual(len(events), 1)
event = events.first()
self.assertEqual(event.user["username"], self.user.username)
self.assertIn("Policy failed to execute", event.context["message"])
self.assertIn("division by zero", event.context["message"])

View File

@ -23,6 +23,7 @@ from authentik.core.models import Application
from authentik.events.models import Event, EventAction
from authentik.lib.expression.exceptions import ControlFlowException
from authentik.lib.sync.mapper import PropertyMappingManager
from authentik.lib.utils.errors import exception_to_string
from authentik.policies.api.exec import PolicyTestResultSerializer
from authentik.policies.engine import PolicyEngine
from authentik.policies.types import PolicyResult
@ -141,9 +142,9 @@ class RadiusOutpostConfigViewSet(ListModelMixin, GenericViewSet):
# Value error can be raised when assigning invalid data to an attribute
Event.new(
EventAction.CONFIGURATION_ERROR,
message="Failed to evaluate property-mapping",
message=f"Failed to evaluate property-mapping {exception_to_string(exc)}",
mapping=exc.mapping,
).with_exception(exc).save()
).save()
return None
return b64encode(packet.RequestPacket()).decode()

View File

@ -28,6 +28,7 @@ from tenant_schemas_celery.app import CeleryApp as TenantAwareCeleryApp
from authentik import get_full_version
from authentik.lib.sentry import before_send
from authentik.lib.utils.errors import exception_to_string
# set the default Django settings module for the 'celery' program.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
@ -82,8 +83,8 @@ def task_error_hook(task_id: str, exception: Exception, traceback, *args, **kwar
CTX_TASK_ID.set(...)
if before_send({}, {"exc_info": (None, exception, None)}) is not None:
Event.new(
EventAction.SYSTEM_EXCEPTION, message="Failed to execute task", task_id=task_id
).with_exception(exception).save()
EventAction.SYSTEM_EXCEPTION, message=exception_to_string(exception), task_id=task_id
).save()
def _get_startup_tasks_default_tenant() -> list[Callable]:

View File

@ -8,6 +8,7 @@ from authentik.events.models import TaskStatus
from authentik.events.system_tasks import SystemTask
from authentik.lib.config import CONFIG
from authentik.lib.sync.outgoing.exceptions import StopSync
from authentik.lib.utils.errors import exception_to_string
from authentik.root.celery import CELERY_APP
from authentik.sources.kerberos.models import KerberosSource
from authentik.sources.kerberos.sync import KerberosSync
@ -63,5 +64,5 @@ def kerberos_sync_single(self, source_pk: str):
syncer.sync()
self.set_status(TaskStatus.SUCCESSFUL, *syncer.messages)
except StopSync as exc:
LOGGER.warning("Error syncing kerberos", exc=exc, source=source)
LOGGER.warning(exception_to_string(exc))
self.set_error(exc)

View File

@ -12,6 +12,7 @@ from authentik.events.models import TaskStatus
from authentik.events.system_tasks import SystemTask
from authentik.lib.config import CONFIG
from authentik.lib.sync.outgoing.exceptions import StopSync
from authentik.lib.utils.errors import exception_to_string
from authentik.lib.utils.reflection import class_to_path, path_to_class
from authentik.root.celery import CELERY_APP
from authentik.sources.ldap.models import LDAPSource
@ -148,5 +149,5 @@ def ldap_sync(self: SystemTask, source_pk: str, sync_class: str, page_cache_key:
cache.delete(page_cache_key)
except (LDAPException, StopSync) as exc:
# No explicit event is created here as .set_status with an error will do that
LOGGER.warning("Failed to sync LDAP", exc=exc, source=source)
LOGGER.warning(exception_to_string(exc))
self.set_error(exc)

View File

@ -13,6 +13,7 @@ from authentik.flows.exceptions import StageInvalidException
from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
from authentik.lib.config import CONFIG
from authentik.lib.models import SerializerModel
from authentik.lib.utils.errors import exception_to_string
from authentik.lib.utils.time import timedelta_string_validator
from authentik.stages.authenticator.models import SideChannelDevice
from authentik.stages.email.utils import TemplateEmailMessage
@ -159,8 +160,9 @@ class EmailDevice(SerializerModel, SideChannelDevice):
Event.new(
EventAction.CONFIGURATION_ERROR,
message=_("Exception occurred while rendering E-mail template"),
error=exception_to_string(exc),
template=stage.template,
).with_exception(exc).from_http(self.request)
).from_http(self.request)
raise StageInvalidException from exc
def __str__(self):

View File

@ -17,6 +17,7 @@ from authentik.flows.challenge import (
from authentik.flows.exceptions import StageInvalidException
from authentik.flows.stage import ChallengeStageView
from authentik.lib.utils.email import mask_email
from authentik.lib.utils.errors import exception_to_string
from authentik.lib.utils.time import timedelta_from_string
from authentik.stages.authenticator_email.models import (
AuthenticatorEmailStage,
@ -99,8 +100,9 @@ class AuthenticatorEmailStageView(ChallengeStageView):
Event.new(
EventAction.CONFIGURATION_ERROR,
message=_("Exception occurred while rendering E-mail template"),
error=exception_to_string(exc),
template=stage.template,
).with_exception(exc).from_http(self.request)
).from_http(self.request)
raise StageInvalidException from exc
def _has_email(self) -> str | None:

View File

@ -19,6 +19,7 @@ from authentik.events.models import Event, EventAction, NotificationWebhookMappi
from authentik.events.utils import sanitize_item
from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
from authentik.lib.models import SerializerModel
from authentik.lib.utils.errors import exception_to_string
from authentik.lib.utils.http import get_http_session
from authentik.stages.authenticator.models import SideChannelDevice
@ -141,9 +142,10 @@ class AuthenticatorSMSStage(ConfigurableStage, FriendlyNamedStage, Stage):
Event.new(
EventAction.CONFIGURATION_ERROR,
message="Error sending SMS",
exc=exception_to_string(exc),
status_code=response.status_code,
body=response.text,
).with_exception(exc).set_user(device.user).save()
).set_user(device.user).save()
if response.status_code >= HttpResponseBadRequest.status_code:
raise ValidationError(response.text) from None
raise

View File

@ -21,6 +21,7 @@ from authentik.flows.models import FlowDesignation, FlowToken
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER
from authentik.flows.stage import ChallengeStageView
from authentik.flows.views.executor import QS_KEY_TOKEN, QS_QUERY
from authentik.lib.utils.errors import exception_to_string
from authentik.lib.utils.time import timedelta_from_string
from authentik.stages.email.flow import pickle_flow_token_for_email
from authentik.stages.email.models import EmailStage
@ -128,8 +129,9 @@ class EmailStageView(ChallengeStageView):
Event.new(
EventAction.CONFIGURATION_ERROR,
message=_("Exception occurred while rendering E-mail template"),
error=exception_to_string(exc),
template=current_stage.template,
).with_exception(exc).from_http(self.request)
).from_http(self.request)
raise StageInvalidException from exc
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:

View File

@ -40,7 +40,7 @@ When creating or editing this stage in the UI of the Admin interface, you can se
When configured, all sessions authenticated by this stage will be bound to the selected network and/or GeoIP criteria.
Sessions that break this binding will be terminated on use. The created [`logout`](../../../../sys-mgmt/events/index.md#logout) event will contain additional data related to what caused the binding to be broken:
Sessions that break this binding will be terminated on use. The created [`logout`](../../../../sys-mgmt/events/event-actions#logout) event will contain additional data related to what caused the binding to be broken:
```json
{

View File

@ -0,0 +1,308 @@
---
title: Event actions
---
Whenever any of the following actions occur, an event is created. Actions are used to define [Notification Rules](notifications.md).
### `login`
A user logs in (including the source, if available)
<details>
<summary>Example</summary>
```json
{
"pk": "f00f54e7-2b38-421f-bc78-e61f950048d6",
"user": {
"pk": 1,
"email": "root@localhost",
"username": "akadmin"
},
"action": "login",
"app": "authentik.events.signals",
"context": {
"auth_method": "password",
"http_request": {
"args": {
"query": "next=%2F"
},
"path": "/api/v3/flows/executor/default-authentication-flow/",
"method": "GET"
},
"auth_method_args": {}
},
"client_ip": "::1",
"created": "2023-02-15T15:33:42.771091Z",
"expires": "2024-02-15T15:33:42.770425Z",
"brand": {
"pk": "fcba828076b94dedb2d5a6b4c5556fa1",
"app": "authentik_brands",
"name": "Default brand",
"model_name": "brand"
}
}
```
</details>
### `login_failed`
A failed login attempt
<details>
<summary>Example</summary>
```json
{
"pk": "2779b173-eb2a-4c2b-a1a4-8283eda308d7",
"user": {
"pk": 2,
"email": "",
"username": "AnonymousUser"
},
"action": "login_failed",
"app": "authentik.events.signals",
"context": {
"stage": {
"pk": "7e88f4a991c442c1a1335d80f0827d7f",
"app": "authentik_stages_password",
"name": "default-authentication-password",
"model_name": "passwordstage"
},
"password": "********************",
"username": "akadmin",
"http_request": {
"args": {
"query": "next=%2F"
},
"path": "/api/v3/flows/executor/default-authentication-flow/",
"method": "POST"
}
},
"client_ip": "::1",
"created": "2023-02-15T15:32:55.319608Z",
"expires": "2024-02-15T15:32:55.314581Z",
"brand": {
"pk": "fcba828076b94dedb2d5a6b4c5556fa1",
"app": "authentik_brands",
"name": "Default brand",
"model_name": "brand"
}
}
```
</details>
### `logout`
A user logs out.
<details>
<summary>Example</summary>
```json
{
"pk": "474ffb6b-77e3-401c-b681-7d618962440f",
"user": {
"pk": 1,
"email": "root@localhost",
"username": "akadmin"
},
"action": "logout",
"app": "authentik.events.signals",
"context": {
"http_request": {
"args": {
"query": ""
},
"path": "/api/v3/flows/executor/default-invalidation-flow/",
"method": "GET"
}
},
"client_ip": "::1",
"created": "2023-02-15T15:39:55.976243Z",
"expires": "2024-02-15T15:39:55.975535Z",
"brand": {
"pk": "fcba828076b94dedb2d5a6b4c5556fa1",
"app": "authentik_brands",
"name": "Default brand",
"model_name": "brand"
}
}
```
</details>
### `user_write`
A user is written to during a flow execution.
<details>
<summary>Example</summary>
```json
{
"pk": "d012e8af-cb94-4fa2-9e92-961e4eebc060",
"user": {
"pk": 1,
"email": "root@localhost",
"username": "akadmin"
},
"action": "user_write",
"app": "authentik.events.signals",
"context": {
"name": "authentik Default Admin",
"email": "root@localhost",
"created": false,
"username": "akadmin",
"attributes": {
"settings": {
"locale": ""
}
},
"http_request": {
"args": {
"query": ""
},
"path": "/api/v3/flows/executor/default-user-settings-flow/",
"method": "GET"
}
},
"client_ip": "::1",
"created": "2023-02-15T15:41:18.411017Z",
"expires": "2024-02-15T15:41:18.410276Z",
"brand": {
"pk": "fcba828076b94dedb2d5a6b4c5556fa1",
"app": "authentik_brands",
"name": "Default brand",
"model_name": "brand"
}
}
```
</details>
### `suspicious_request`
A suspicious request has been received (for example, a revoked token was used).
### `password_set`
A user sets their password.
### `secret_view`
A user views a token's/certificate's data.
### `secret_rotate`
A token was rotated automatically by authentik.
### `invitation_used`
An invitation is used.
### `authorize_application`
A user authorizes an application.
<details>
<summary>Example</summary>
```json
{
"pk": "f52f9eb9-dc2a-4f1e-afea-ad5af90bf680",
"user": {
"pk": 1,
"email": "root@localhost",
"username": "akadmin"
},
"action": "authorize_application",
"app": "authentik.providers.oauth2.views.authorize",
"context": {
"asn": {
"asn": 6805,
"as_org": "Telefonica Germany",
"network": "5.4.0.0/14"
},
"geo": {
"lat": 42.0,
"city": "placeholder",
"long": 42.0,
"country": "placeholder",
"continent": "placeholder"
},
"flow": "53287faa8a644b6cb124cb602a84282f",
"scopes": "ak_proxy profile openid email",
"http_request": {
"args": {
"query": "[...]"
},
"path": "/api/v3/flows/executor/default-provider-authorization-implicit-consent/",
"method": "GET"
},
"authorized_application": {
"pk": "bed6a2495fdc4b2e8c3f93cb2ed7e021",
"app": "authentik_core",
"name": "Alertmanager",
"model_name": "application"
}
},
"client_ip": "::1",
"created": "2023-02-15T10:02:48.615499Z",
"expires": "2023-04-26T10:02:48.612809Z",
"brand": {
"pk": "10800be643d44842ab9d97cb5f898ce9",
"app": "authentik_brands",
"name": "Default brand",
"model_name": "brand"
}
}
```
</details>
### `source_linked`
A user links a source to their account
### `impersonation_started` / `impersonation_ended`
A user starts/ends impersonation, including the user that was impersonated
### `policy_execution`
A policy is executed (when a policy has "Execution Logging" enabled).
### `policy_exception` / `property_mapping_exception`
A policy or property mapping causes an exception
### `system_task_exception`
An exception occurred in a system task.
### `system_exception`
A general exception in authentik occurred.
### `configuration_error`
A configuration error occurs, for example during the authorization of an application
### `model_created` / `model_updated` / `model_deleted`
Logged when any model is created/updated/deleted, including the user that sent the request.
:::info
Starting with authentik 2024.2, when a valid enterprise license is installed, these entries will contain additional audit data, including which fields were changed with this event, their previous values and their new values.
:::
### `email_sent`
An email has been sent. Included is the email that was sent.
### `update_available`
An update is available

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

View File

@ -4,319 +4,20 @@ title: Events
Events are authentik's built-in logging system. Every event is logged, whether it is initiated by a user or by authentik.
Events can be used to define [notification rules](notifications.md), with specified [transport options](transports.md) of local (in the authentik UI), email or webhook.
Certain information is stripped from events, to ensure that no passwords or other credentials are saved in the log.
Certain information is stripped from events, to ensure no passwords or other credentials are saved in the log.
## About notifications
## Event retention
Events can be used to define [notification rules](notifications.md), with specified [transport options](transports.md) of either local (in the authentik UI), email, or webhook.
The event retention is configured in the **System > Settings** area of the Admin interface, with the default being set to 365 days.
## About logging
If you want to forward these events to another application, forward the log output of all authentik containers. Every event creation is logged with the log level "info". For this configuration, it is also recommended to set the internal retention pretty low (for example, `days=1`).
Logging of events in authentik provides several layers of transparency about user and system actions, from a quick view on the Overview dashboard, to a full, searchable list of all events, with a volume graph to highlight any spikes, in the Admin interface under **Events > Logs**.
## Event actions
For more information refer to our [Logging documentation](./logging-events.md).
Whenever any of the following actions occur, an event is created.
## Event retention and forwarding
### `login`
The event retention setting is configured in the **System > Settings** area of the Admin interface, with the default being set to 365 days.
A user logs in (including the source, if available)
<details>
<summary>Example</summary>
```json
{
"pk": "f00f54e7-2b38-421f-bc78-e61f950048d6",
"user": {
"pk": 1,
"email": "root@localhost",
"username": "akadmin"
},
"action": "login",
"app": "authentik.events.signals",
"context": {
"auth_method": "password",
"http_request": {
"args": {
"query": "next=%2F"
},
"path": "/api/v3/flows/executor/default-authentication-flow/",
"method": "GET"
},
"auth_method_args": {}
},
"client_ip": "::1",
"created": "2023-02-15T15:33:42.771091Z",
"expires": "2024-02-15T15:33:42.770425Z",
"brand": {
"pk": "fcba828076b94dedb2d5a6b4c5556fa1",
"app": "authentik_brands",
"name": "Default brand",
"model_name": "brand"
}
}
```
</details>
### `login_failed`
A failed login attempt
<details>
<summary>Example</summary>
```json
{
"pk": "2779b173-eb2a-4c2b-a1a4-8283eda308d7",
"user": {
"pk": 2,
"email": "",
"username": "AnonymousUser"
},
"action": "login_failed",
"app": "authentik.events.signals",
"context": {
"stage": {
"pk": "7e88f4a991c442c1a1335d80f0827d7f",
"app": "authentik_stages_password",
"name": "default-authentication-password",
"model_name": "passwordstage"
},
"password": "********************",
"username": "akadmin",
"http_request": {
"args": {
"query": "next=%2F"
},
"path": "/api/v3/flows/executor/default-authentication-flow/",
"method": "POST"
}
},
"client_ip": "::1",
"created": "2023-02-15T15:32:55.319608Z",
"expires": "2024-02-15T15:32:55.314581Z",
"brand": {
"pk": "fcba828076b94dedb2d5a6b4c5556fa1",
"app": "authentik_brands",
"name": "Default brand",
"model_name": "brand"
}
}
```
</details>
### `logout`
A user logs out.
<details>
<summary>Example</summary>
```json
{
"pk": "474ffb6b-77e3-401c-b681-7d618962440f",
"user": {
"pk": 1,
"email": "root@localhost",
"username": "akadmin"
},
"action": "logout",
"app": "authentik.events.signals",
"context": {
"http_request": {
"args": {
"query": ""
},
"path": "/api/v3/flows/executor/default-invalidation-flow/",
"method": "GET"
}
},
"client_ip": "::1",
"created": "2023-02-15T15:39:55.976243Z",
"expires": "2024-02-15T15:39:55.975535Z",
"brand": {
"pk": "fcba828076b94dedb2d5a6b4c5556fa1",
"app": "authentik_brands",
"name": "Default brand",
"model_name": "brand"
}
}
```
</details>
### `user_write`
A user is written to during a flow execution.
<details>
<summary>Example</summary>
```json
{
"pk": "d012e8af-cb94-4fa2-9e92-961e4eebc060",
"user": {
"pk": 1,
"email": "root@localhost",
"username": "akadmin"
},
"action": "user_write",
"app": "authentik.events.signals",
"context": {
"name": "authentik Default Admin",
"email": "root@localhost",
"created": false,
"username": "akadmin",
"attributes": {
"settings": {
"locale": ""
}
},
"http_request": {
"args": {
"query": ""
},
"path": "/api/v3/flows/executor/default-user-settings-flow/",
"method": "GET"
}
},
"client_ip": "::1",
"created": "2023-02-15T15:41:18.411017Z",
"expires": "2024-02-15T15:41:18.410276Z",
"brand": {
"pk": "fcba828076b94dedb2d5a6b4c5556fa1",
"app": "authentik_brands",
"name": "Default brand",
"model_name": "brand"
}
}
```
</details>
### `suspicious_request`
A suspicious request has been received (for example, a revoked token was used).
### `password_set`
A user sets their password.
### `secret_view`
A user views a token's/certificate's data.
### `secret_rotate`
A token was rotated automatically by authentik.
### `invitation_used`
An invitation is used.
### `authorize_application`
A user authorizes an application.
<details>
<summary>Example</summary>
```json
{
"pk": "f52f9eb9-dc2a-4f1e-afea-ad5af90bf680",
"user": {
"pk": 1,
"email": "root@localhost",
"username": "akadmin"
},
"action": "authorize_application",
"app": "authentik.providers.oauth2.views.authorize",
"context": {
"asn": {
"asn": 6805,
"as_org": "Telefonica Germany",
"network": "5.4.0.0/14"
},
"geo": {
"lat": 42.0,
"city": "placeholder",
"long": 42.0,
"country": "placeholder",
"continent": "placeholder"
},
"flow": "53287faa8a644b6cb124cb602a84282f",
"scopes": "ak_proxy profile openid email",
"http_request": {
"args": {
"query": "[...]"
},
"path": "/api/v3/flows/executor/default-provider-authorization-implicit-consent/",
"method": "GET"
},
"authorized_application": {
"pk": "bed6a2495fdc4b2e8c3f93cb2ed7e021",
"app": "authentik_core",
"name": "Alertmanager",
"model_name": "application"
}
},
"client_ip": "::1",
"created": "2023-02-15T10:02:48.615499Z",
"expires": "2023-04-26T10:02:48.612809Z",
"brand": {
"pk": "10800be643d44842ab9d97cb5f898ce9",
"app": "authentik_brands",
"name": "Default brand",
"model_name": "brand"
}
}
```
</details>
### `source_linked`
A user links a source to their account
### `impersonation_started` / `impersonation_ended`
A user starts/ends impersonation, including the user that was impersonated
### `policy_execution`
A policy is executed (when a policy has "Execution Logging" enabled).
### `policy_exception` / `property_mapping_exception`
A policy or property mapping causes an exception
### `system_task_exception`
An exception occurred in a system task.
### `system_exception`
A general exception in authentik occurred.
### `configuration_error`
A configuration error occurs, for example during the authorization of an application
### `model_created` / `model_updated` / `model_deleted`
Logged when any model is created/updated/deleted, including the user that sent the request.
:::info
Starting with authentik 2024.2, when a valid enterprise license is installed, these entries will contain additional audit data, including which fields were changed with this event, their previous values and their new values.
:::
### `email_sent`
An email has been sent. Included is the email that was sent.
### `update_available`
An update is available
If you want to forward these events to another application, forward the log output of all authentik containers. Every event creation is logged with the log level "info". For this configuration, it is also recommended to set the internal retention time period to a short time frame (for example, `days=1`).

View File

@ -0,0 +1,31 @@
---
title: Logging events
---
Logs are an important tool for system diagnoses, event auditing, user management, reports, and so much more. Detailed information about events are captured, including the IP address of the client that triggered the event, the user, the date and timestamp, and the exact action made.
Event logging in authentik is highly configurable; you can define the [retention period](./index.md#event-retention-and-forwarding) for storing and displaying events, configure which exact events should trigger a [notification](./notifications.md), and view low-level details about when and where the event happened.
### Troubleshooting with event logs
For details about troubleshooting using logs, including setting the log level (info, warning, etc.), enabling `trace` mode, viewing past logs, and streaming logs in real-time, refer to [Capturing logs in authentik](../../troubleshooting/logs.mdx).
## Enhanced audit logging (Enterprise)
In the enterprise version, each Event details page in the UI, details about each event are abstracted and displayed in an easy-to-access table, and for any event that involves an object being created or modified, the code `diffs` are displayed as well. This allows you to quickly see the previous and new configuration settings.
For example, say an authentik administraotr updates a user's email address; the old email address and the new one are shown when you drill down in that event's details.
![](./events-diffs.png)
Areas of the authentik UI where you can view these audits details are:
- **Admin interface > Dashboards > Overview**: In the **Recent events** section, click the name of an event to view details.
- **Admin interface > Events > Logs**: In the list of events, click the arrow toggle beside the name of the even that you want to view details for.
## Viewing events in maps and charts (Enterprise)
With the enterprise version, you can view recent events on both a world map view with pinpoints of where events occurred and also as a color-coded chart displaying type of event and volume of each type.
![](./event-map-chart.png)

View File

@ -3,16 +3,34 @@ title: Notifications
---
:::note
To prevent infinite loops (events created by policies which are attached to a Notification rule), **any events created by a policy which is attached to any Notification Rules do not trigger notifications.**
To prevent infinite loops of cause and effect (events created by policies which are attached to a notification rule), _any events created by a policy which is attached to any notification rules do not trigger notifications._
:::
## Filtering Events
An authentik administrator can create notification rules based on the creation of specified events. Filtering of events is processed by the authentik Policy Engine, using a combination of both 1) a policy and 2) a notification rule.
An authentik administrator can create notification rules based on the creation of specified events. Filtering is done by using the Policy Engine. You can do simple filtering using the "Event Matcher Policy" type.
## Workflow overview
![](./event_matcher.png)
To receive notifications about events, follow this workflow:
An event has to match all configured fields, otherwise the rule will not trigger.
1. Create a transport (or use an existing default transport)
2. Create a policy
3. Create a notification rule, and bind the policy to the rule
## 1. Create a notification transport
A transport method (email, UI, webhook) is how the notifications are delivered to a user. Follow these [instructions](./transports.md#create-a-transport) for creating a transport.
## 2. Create a policy
You will need to create a policy (either the **Event Matcher** policy or a custom Expression policy) that defines which events will trigger a notification.
### **Event Matcher** policy
For simple filtering you can [create and configure](../../customize/policies/working_with_policies.md) a new **Event Matcher** policy to specify exactly which events (known as _Actions_ in the policy) you want to be notified about. For example, you can chose to create a policy for every time a user deletes a model object, or whenever any user fails to successfully log in.
Be aware that an event has to match all configured fields in the policy, otherwise the notification rule will not trigger.
### Expression policy for events
To match events with an "Expression Policy", you can write code like so:
@ -23,17 +41,23 @@ if "event" not in request.context:
return ip_address(request.context["event"].client_ip) in ip_network('192.0.2.0/24')
```
## Selecting who gets notified
## 3. Create a notification rule and bind it to the policy
After you've created the policies to match the events you want, create a "Notification Rule".
After you've created the policies to match the events you want, create a notification rule.
You have to select which group the generated notification should be sent to. If left empty, the rule will be disabled.
1. Log in as an administrator, open the authentik Admin interface, and navigate to **Event > Notification Rules**.
2. Click **Create** to add a new notification rule, or click the **Edit** icon next to an existing rule to modify it.
3. Define the policy configurations, and click **Create** or \*\*Update to save the settings.
- Note that you have to select which group the generated notification should be sent to. If left empty, the rule will be disabled.
- You also have to select which [transports](./transports.md) should be used to send the notification. A transport with the name "default-email-transport" is created by default. This transport will use the [global email configuration](../../install-config/install/docker-compose.mdx#email-configuration-optional-but-recommended).
4. In the list of Notification rules, click the arrow in the row of the Notification rule to expand the details of the rule.
5. Click **Bind existing Policy/Group/User**, and in the **Create Binding** modal, select the policy that you created for this notification rule and then click **Create** to finalize the binding.
:::info
Before authentik 2023.5, when no group is selected, policies bound to the rule are not executed. Starting with authentik 2023.5, policies are executed even when no group is selected.
Be aware that policies are executed even when no group is selected.
:::
You also have to select which transports should be used to send the notification.
A transport with the name "default-email-transport" is created by default. This transport will use the [global email configuration](../../install-config/install/docker-compose.mdx#email-configuration-optional-but-recommended).
Starting with authentik 2022.6, a new default transport will be created. This is because notifications are no longer created by default, they are now a transport method instead. This allows for better customization of the notification before it is created.

View File

@ -2,9 +2,28 @@
title: Transports
---
Notifications can be sent to users via multiple mediums. By default, the [global email configuration](../../install-config/install/docker-compose.mdx#email-configuration-optional-but-recommended) will be used.
To receive notifications about events, you will need to [create](#create-a-transport) a transport object, then create a notification rule and a policy. For details refer to [Workflow overview](./notifications.md#workflow-overview).
## Generic Webhook
## Transport modes
Notifications can be sent to users via multiple mediums, or _transports_:
- Local (in the authentik user interface)
- Email
- Webhook (generic)
- Webhook (Slack/Discord)
### Local transport
This transport will manifest the notification within the authentik user interface (UI).
### Email
Select this transport to send event notifications to an email address. Note that by default, the [global email configuration](../../install-config/install/docker-compose.mdx#email-configuration-optional-but-recommended) is used.
To edit an email address, follow the same instructions as above, those for configuring the email during installation.
### Webhook (generic)
This will send a POST request to the given URL with the following contents:
@ -31,6 +50,14 @@ return {
}
```
## Slack Webhook
### Webhook (Slack or Discord)
This sends a request using the Slack-specific format. This is also compatible with Discord's webhooks by appending `/slack` to the Discord webhook URL.
## Create a transport
1. Log in as an administrator to the authentik Admin interface, and navigate to **Event > Notification Transports**.
2. Click **Create** to add a new transport, or click the **Edit** icon next to an existing transport to modify it.
3. Define the **Name** and **Mode** for the transport, enter required configuration settings, and then click **Create**.

View File

@ -606,7 +606,12 @@ const items = [
type: "doc",
id: "sys-mgmt/events/index",
},
items: ["sys-mgmt/events/notifications", "sys-mgmt/events/transports"],
items: [
"sys-mgmt/events/notifications",
"sys-mgmt/events/transports",
"sys-mgmt/events/logging-events",
"sys-mgmt/events/event-actions",
],
},
"sys-mgmt/certificates",
"sys-mgmt/settings",