Expressions
The property mapping should return a value that is expected by the provider. Supported types are documented in the individual provider. Returning None
is always accepted and would simply skip the mapping for which None
was returned.
Available Functions
regex_match(value: Any, regex: str) -> bool
Check if value
matches Regular Expression regex
.
Example:
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:
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 its not a list.
Example:
user = list_flatten(["foo"])
# user = "foo"
ak_call_policy(name: str, **kwargs) -> PolicyResult
Call another policy with the name name. Current request is passed to policy. Key-word arguments can be used to modify the request's context.
Example:
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:
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 object.
Example:
# Find user by username
other_user = ak_user_by(username="other_user")
# Find user by custom attribute
other_user = ak_user_by(attributes__<custom_attribute_name>="<value>")
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 a specific device type. The following options are valid:
totp
duo
static
webauthn
Example:
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 key-word 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-structure which are not representable in JSON are flattened, and credentials are removed.
The event is saved automatically
Example:
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
authentik: 2025.2.0+
Create a new JWT signed by the given provider
for user
.
The provider
parameter can either be an instance of OAuth2Provider
or a the name of a provider instance as a string. Scopes is an array of all scopes that the JWT should have.
The JWT is valid for 60 seconds by default, 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:
jwt = ak_create_jwt(request.user, "my-oauth2-provider-name", ["openid", "profile", "email"])
ak_send_email(address: str | list[str], subject: str, body: str = None, stage: EmailStage = None, template: str = None, context: dict = None) -> bool
authentik: 2025.10.0+
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"]
When using multiple recipients, all email addresses will be visible in the "To:" field of the email. If you need to send to multiple recipients without revealing all addresses to each other, send individual emails instead.
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.
If the email is queued successfully, the function returns True
; otherwise, it returns False
.
Examples:
# 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)
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.
You can also check if an IP Address is within a subnet by writing the following:
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)
.
resolve_dns("google.com") # return a list of all IPv4 and IPv6 addresses
resolve_dns("google.com", 4) # return a list of only IP4 addresses
resolve_dns("google.com", 6) # return a list of only IP6 addresses
:::info
You can also do 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.
:::
Variables
-
ak_logger
: structlog BoundLogger. See (structlog documentation)Example:
ak_logger.debug("This is a test message")
ak_logger.warning("This will be logged with a warning level")
ak_logger.info("Passing structured data", request=request) -
requests
: requests Session object. See (request documentation)
user
: The current user. This may beNone
if there is no contextual user. See User.
Example:
return {
"custom_attribute": request.user.attributes.get("custom_attribute", "default"),
}
request
: The current request. This may beNone
if there is no contextual request. See (Django documentation)- Other arbitrary arguments given by the provider, this is documented on the provider.