### `regex_match(value: Any, regex: str) -> bool` Check if `value` matches Regular Expression `regex`. Example: ```python return regex_match(request.user.username, '.*admin.*') ``` ### `regex_replace(value: Any, regex: str, repl: str) -> str` Replace anything matching `regex` within `value` with `repl` and return it. Example: ```python user_email_local = regex_replace(request.user.email, '(.+)@.+', '') ``` ### `list_flatten(value: list[Any] | Any) -> Optional[Any]` Flatten a list by either returning its first element, None if the list is empty, or the passed in object if it's not a list. Example: ```python user = list_flatten(["foo"]) # user = "foo" ``` ### `ak_call_policy(name: str, **kwargs) -> PolicyResult` Call another policy with the name _name_. The current request is passed to the policy. Keyword arguments can be used to modify the request's context. Example: ```python result = ak_call_policy("test-policy") # result is a PolicyResult object, so you can access `.passing` and `.messages`. # Starting with authentik 2023.4, you can also access `.raw_result`, which is the raw value returned from the called policy # `result.passing` will always be a boolean if the policy is passing or not. return result.passing result = ak_call_policy("test-policy-2", foo="bar") # Inside the `test-policy-2` you can then use `request.context["foo"]` return result.passing ``` ### `ak_is_group_member(user: User, **group_filters) -> bool` Check if `user` is member of a group matching `**group_filters`. Example: ```python return ak_is_group_member(request.user, name="test_group") ``` ### `ak_user_by(**filters) -> Optional[User]` Fetch a user matching `**filters`. Returns `None` if no user was found; otherwise, returns the [User](../../users-sources/user/index.mdx) object. Example: ```python # Find user by username other_user = ak_user_by(username="other_user") # Find user by custom attribute other_user = ak_user_by(attributes__="") ``` ### `ak_user_has_authenticator(user: User, device_type: Optional[str] = None) -> bool` Check if a user has any authenticator devices. Only fully validated devices are counted. Optionally, you can filter by a specific device type. The following options are valid: - `totp` - `duo` - `static` - `webauthn` Example: ```python return ak_user_has_authenticator(request.user) ``` ### `ak_create_event(action: str, **kwargs) -> None` Create a new event with the action set to `action`. Any additional keyword parameters will be saved in the event context. Additionally, `context` will be set to the context in which this function is called. Before saving, any data structures which are not representable in JSON are flattened, and credentials are removed. The event is saved automatically. Example: ```python ak_create_event("my_custom_event", foo=request.user) ``` ### `ak_create_jwt(user: User, provider: OAuth2Provider | str, scopes: list[str], validity = "seconds=60") -> str | None`:ak-version[2025.2] :::info Requires HTTP Request This function will only work when there is an HTTP request in the current context. ::: Create a new JWT signed by the given `provider` for `user`. The `provider` parameter can either be an instance of `OAuth2Provider` or the name of a provider instance as a string. Scopes are an array of all scopes that the JWT should have. The JWT is valid for 60 seconds by default, and this can be customized using the `validity` parameter. The syntax of the parameter is `hours=1,minutes=2,seconds=3`. The following keys are allowed: - Microseconds - Milliseconds - Seconds - Minutes - Hours - Days - Weeks All values accept floating-point values. Example: ```python jwt = ak_create_jwt(request.user, "my-oauth2-provider-name", ["openid", "profile", "email"]) ``` ### `ak_create_jwt_raw(provider: OAuth2Provider | str, validity = "seconds=60", **kwargs) -> str | None`:ak-version[2025.12] Similar to [`ak_create_jwt`](#ak_create_jwtuser-user-provider-oauth2provider--str-scopes-liststr-validity--seconds60---str--none), however this function does _not_ require an HTTP request and allows for setting custom claims via `**kwargs`. The `provider` parameter can either be an instance of `OAuth2Provider` or the name of a provider instance as a string. Scopes are an array of all scopes that the JWT should have. The JWT is valid for 60 seconds by default, and this can be customized using the `validity` parameter. The syntax of the parameter is `hours=1,minutes=2,seconds=3`. The following keys are allowed: - Microseconds - Milliseconds - Seconds - Minutes - Hours - Days - Weeks All values accept floating-point values. Example: ```python jwt = ak_create_jwt_raw("my-oauth2-provider-name", my_claim="my_value") ``` ### `ak_send_email(address: str | list[str], subject: str, body: str = None, stage: EmailStage = None, template: str = None, context: dict = None, cc: str | list[str] = None, bcc: str | list[str] = None) -> bool`:ak-version[2025.10] Send an email using authentik's email system. The `address` parameter specifies the recipient email address(es). It can be: - A single email address as a string: `"user@example.com"` - A list of email addresses: `["user1@example.com", "user2@example.com"]` :::info When using multiple recipients in the `address` or `cc` fields, all email addresses will be visible to all recipients. Use `bcc` to send to multiple recipients without revealing addresses to each other. ::: The `subject` parameter sets the email subject line. You must provide either `body` (for plain text/HTML content) or `template` (for template rendering), but not both. The `stage` parameter can be an `EmailStage` instance for custom email settings. If `None`, global email settings are used. The `template` parameter specifies a template name to render. When using templates, you can pass additional context variables via the `context` parameter. The `cc` parameter specifies email address(es) to carbon copy. Same format as `address`. The `bcc` parameter specifies email address(es) to blind carbon copy. Same format as `address`. Recipients in `bcc` will not be visible to other recipients. If the email is queued successfully, the function returns `True`; otherwise, it returns `False`. Examples: ```python # Send email with plain body to single recipient ak_send_email("user@example.com", "Welcome!", body="Welcome to our platform!") # Send email to multiple recipients ak_send_email( ["user1@example.com", "user2@example.com", "admin@example.com"], "System Maintenance", body="Scheduled maintenance will occur tonight." ) # Send email using a template ak_send_email("user@example.com", "Password Reset", template="email/password_reset.html") # Send email with custom context for template to multiple recipients ak_send_email( ["user@example.com", "admin@example.com"], "Account Update", template="email/event_notification.html", context={ "title": "Profile Updated", "body": "Your account profile has been successfully updated.", "key_value": {"Updated Field": "Email Address", "Date": "2025-01-01"} } ) # Send email with custom email stage ak_send_email("admin@example.com", "Report", body="Daily report", stage=my_custom_stage) # Send email with CC ak_send_email( "user@example.com", "Important Update", body="Please review this update.", cc="manager@example.com" ) # Send email with multiple CC and BCC recipients ak_send_email( "user@example.com", "Confidential Report", body="Attached is the quarterly report.", cc=["manager@example.com", "lead@example.com"], bcc=["audit@example.com", "compliance@example.com"] ) ``` ## Comparing IP Addresses To compare IP addresses or check if an IP address is within a given subnet, you can use the functions `ip_address('192.0.2.1')` and `ip_network('192.0.2.0/24')`. With these objects you can do [arithmetic operations](https://docs.python.org/3/library/ipaddress.html#operators). You can also check if an IP Address is within a subnet by writing the following: ```python ip_address('192.0.2.1') in ip_network('192.0.2.0/24') # evaluates to True ``` ## DNS resolution and reverse DNS lookups To resolve a hostname to a list of IP addresses, use the functions `resolve_dns(hostname)` and `resolve_dns(hostname, ip_version)`. ```python resolve_dns("google.com") # returns a list of all IPv4 and IPv6 addresses resolve_dns("google.com", 4) # returns a list of only IPv4 addresses resolve_dns("google.com", 6) # returns a list of only IPv6 addresses ``` You can also perform reverse DNS lookups. :::note Reverse DNS lookups may not return the expected host if the IP address is part of a shared hosting environment. See: https://stackoverflow.com/a/19867936 ::: To perform a reverse DNS lookup use `reverse_dns("192.0.2.0")`. If no DNS records are found the original IP address is returned. :::info DNS resolving results are cached in memory. The last 32 unique queries are cached for up to 3 minutes. :::