diff --git a/website/docs/add-secure-apps/bindings-overview/index.md b/website/docs/add-secure-apps/bindings-overview/index.md index d7b3f61e45..4fbcdc3186 100644 --- a/website/docs/add-secure-apps/bindings-overview/index.md +++ b/website/docs/add-secure-apps/bindings-overview/index.md @@ -4,6 +4,8 @@ title: authentik bindings A binding is, simply put, a connection between two components. The use of a binding adds additional functionality to one the existing components; for example, a policy binding can cause a new stage to be presented within a flow to a specific user or group. +A policy answers a question like "should this pass?" A binding decides where authentik asks that question. + :::info For information about creating and managing bindings, refer to [Work with bindings](./work-with-bindings.md). ::: diff --git a/website/docs/add-secure-apps/flows-stages/flow/context/index.mdx b/website/docs/add-secure-apps/flows-stages/flow/context/index.mdx index 3d93b68f43..9fb39c4469 100644 --- a/website/docs/add-secure-apps/flows-stages/flow/context/index.mdx +++ b/website/docs/add-secure-apps/flows-stages/flow/context/index.mdx @@ -13,7 +13,7 @@ For example, in the Identification Stage (part of the default login flow), you c Any data can be stored in the flow context, however there are some reserved keys in the context dictionary that are used by authentik stages. -To manage flow context on a more granular level, see [Setting flow context keys](../../../../customize/policies/expression/managing_flow_context_keys.md). +To manage flow context on a more granular level, see [Setting flow context keys](../../../../customize/policies/types/expression/managing_flow_context_keys.md). ## Context dictionary and reserved keys @@ -227,7 +227,7 @@ This value can be set either via [Prompt data](#prompt_data-dictionary) or via p ##### `redirect_stage_target` (string) -[Set this key](../../../../customize/policies/expression/managing_flow_context_keys.md) in an Expression Policy to override [Redirect stage](../../stages/redirect/index.md) to force it to redirect to a certain URL or flow. This is useful when a flow requires that the redirection target be decided dynamically. +[Set this key](../../../../customize/policies/types/expression/managing_flow_context_keys.md) in an Expression Policy to override [Redirect stage](../../stages/redirect/index.md) to force it to redirect to a certain URL or flow. This is useful when a flow requires that the redirection target be decided dynamically. Use the format `ak-flow://{slug}` to use the Redirect stage in Flow mode. Any other format will result in the Redirect stage running in Static mode. diff --git a/website/docs/add-secure-apps/flows-stages/flow/index.md b/website/docs/add-secure-apps/flows-stages/flow/index.md index e9da4e01a6..0ccb20adf3 100644 --- a/website/docs/add-secure-apps/flows-stages/flow/index.md +++ b/website/docs/add-secure-apps/flows-stages/flow/index.md @@ -50,9 +50,9 @@ To create a flow, follow these steps: 1. Log in to authentik as an administrator and open the Admin interface. 2. In the Admin interface, navigate to **Flows and Stages > Flows**. -3. Click **Create**, define the flow using the [configuration settings](#flow-configuration-options) described below, and then click **Finish**. +3. Click **New Flow**, define the flow using the [configuration settings](#flow-configuration-options) described below, and then click **Create Flow**. -After creating the flow, you can then [bind specific stages](../stages/index.md#bind-a-stage-to-a-flow) to the flow and [bind policies](../../../customize/policies/working_with_policies.md) to the flow to further customize the user's log in and authentication process. +After creating the flow, you can then [bind specific stages](../stages/index.md#bind-a-stage-to-a-flow) to the flow and [bind policies](../../../customize/policies/bindings.md) to the flow to further customize the user's log in and authentication process. To determine which flow should be used, authentik will first check which default authentication flow is configured in the active [**Brand**](../../../sys-mgmt/brands/index.md). If no default is configured there, the policies in all flows with the matching designation are checked, and the first flow with matching policies sorted by `slug` will be used. diff --git a/website/docs/add-secure-apps/flows-stages/stages/consent/index.md b/website/docs/add-secure-apps/flows-stages/stages/consent/index.md index 94ce66ddc5..17f31dd349 100644 --- a/website/docs/add-secure-apps/flows-stages/stages/consent/index.md +++ b/website/docs/add-secure-apps/flows-stages/stages/consent/index.md @@ -28,18 +28,18 @@ If you want to add the consent stage to a flow other than the `default-provider- The basic workflow for creating and configuring a Consent stage involves creating the stage and then binding it to an authorization flow. -Optionally, if you also want to customize the exact wording that appears on the consent prompt, you can create an [Expression policy](../../../../customize/policies/expression.mdx) with the text that you want to display on the Consent prompt, and then [bind](../../../../customize/policies/working_with_policies.md#bind-a-policy-to-a-stage-binding) the policy to the Consent stage binding in the authorization flow. +Optionally, if you also want to customize the exact wording that appears on the consent prompt, you can create an [Expression policy](../../../../customize/policies/types/expression/index.mdx) with the text that you want to display on the Consent prompt, and then [bind](../../../../customize/policies/working_with_policies.md#bind-a-policy-to-a-stage-binding) the policy to the Consent stage binding in the authorization flow. ### 1. Create a Consent stage 1. Log in to authentik as an administrator and open the authentik Admin interface. -2. Navigate to **Flows and Stages** > **Stages** and click **Create**. +2. Navigate to **Flows and Stages** > **Stages** and click **New Stage**. 3. On the **New stage** wizard select **Consent Stage** and then click **Next**. 4. Provide the following configuration settings: - **Name**: - **Stage-specific settings**: - **Mode**: Select the appropriate [mode](#consent-stage-modes) to use with this stage. -5. Click **Finish** to save the new stage. +5. Click **Create Stage** to save the new stage. ### 2. Bind the Consent stage to an authorization flow @@ -50,7 +50,7 @@ To include the Consent stage in the flow, follow [these directions](../../stages If you want to customize the text that appears on the consent prompt, you can create an Expression policy with the exact wording you want, and then bind it to the Consent stage in the flow. 1. Log in to authentik as an administrator and open the authentik Admin interface. -2. Navigate to **Customization** > **Policies** and click **Create**. +2. Navigate to **Customization** > **Policies** and click **New Policy**. 3. On the **New policy** wizard select **Expression Policy** and then click **Next**. 4. Provide the following configuration settings: - **Name**: @@ -61,7 +61,7 @@ If you want to customize the text that appears on the consent prompt, you can cr return True ```python ```` -5. Click **Finish** to save the policy. +5. Click **Create Policy** to save the policy. ### 4. Bind the policy to the Consent stage in the authorization flow (_optional_) @@ -78,4 +78,4 @@ You need to bind the policy to the stage within this flow, so go first to the fl 5. Click the caret (>) beside the Consent stage to which you want to bind the policy, and expand the stage details. 6. Click **Bind existing Policy/Group/User**. 7. In the **Create Binding** dialog, click **Policy** and then select the Expression policy that you created above. -8. Click **Create** to save the binding. +8. Click **Create Policy Binding** to save the binding. diff --git a/website/docs/add-secure-apps/flows-stages/stages/email/index.mdx b/website/docs/add-secure-apps/flows-stages/stages/email/index.mdx index 69e23067ea..5f6205bab4 100644 --- a/website/docs/add-secure-apps/flows-stages/stages/email/index.mdx +++ b/website/docs/add-secure-apps/flows-stages/stages/email/index.mdx @@ -14,7 +14,7 @@ For information about creating a stage, refer to our [documentation](../#create- By default, the email is sent to the currently pending user. To override this, you can set `email` in the plan's context to another email address, which will override the user's email address (the user won't be changed). -For example, create this [expression policy](../../../../customize/policies/expression.mdx) and bind it to the email stage: +For example, create this [expression policy](../../../../customize/policies/types/expression/index.mdx) and bind it to the email stage: ```python request.context["flow_plan"].context["email"] = "foo@bar.baz" diff --git a/website/docs/add-secure-apps/flows-stages/stages/prompt/index.md b/website/docs/add-secure-apps/flows-stages/stages/prompt/index.md index 1017a4b85e..b3378fd68e 100644 --- a/website/docs/add-secure-apps/flows-stages/stages/prompt/index.md +++ b/website/docs/add-secure-apps/flows-stages/stages/prompt/index.md @@ -63,7 +63,7 @@ A flag which decides whether or not this field is required. A field placeholder, shown within the input field. By default, the placeholder is interpreted as-is. If you enable _Interpret placeholder as expression_, the placeholder -will be evaluated as a Python expression. This happens in the same environment as [_Policies_](../../../../customize/policies/expression.mdx). +will be evaluated as a Python expression. This happens in the same environment as [_Policies_](../../../../customize/policies/types/expression/index.mdx). For `Radio Button Group` and `Dropdown` prompts, this field defines the available choices. When used as a plain string, it represents a single allowed value (the placeholder). When used as an expression, it can return a list of choices. For example, `return ["first option", 42, {"label": "another option", "value": "some value"}]` defines three possible values. @@ -80,7 +80,7 @@ The prompt's initial value. It can also be left empty, in which case the field w With the `hidden` prompt, the initial value will also be the actual value, because the field is hidden to the user. By default, the initial value is interpreted as-is. If you enable _Interpret initial value as expression_, the initial value -will be evaluated as a Python expression. This happens in the same environment as [_Policies_](../../../../customize/policies/expression.mdx). +will be evaluated as a Python expression. This happens in the same environment as [_Policies_](../../../../customize/policies/types/expression/index.mdx). In the case of `Radio Button Group` and `Dropdown` prompts, this field defines the default choice. When interpreted as-is, the default choice will be the initial value string. When interpreted as expression, the default choice will be the returned value. For example, `return 42` defines `42` as the default choice. When a choice is defined as an object `{"label": "Option", "value": "internal-value"}`, the initial value needs to be set to the value string `internal-value` in this case. diff --git a/website/docs/add-secure-apps/providers/oauth2/machine_to_machine.mdx b/website/docs/add-secure-apps/providers/oauth2/machine_to_machine.mdx index 913aa8a145..9cd0a6fb24 100644 --- a/website/docs/add-secure-apps/providers/oauth2/machine_to_machine.mdx +++ b/website/docs/add-secure-apps/providers/oauth2/machine_to_machine.mdx @@ -103,7 +103,7 @@ Alternatively, you can set the `client_secret` parameter to ``, for ap Input JWTs are checked to verify that they are signed by any of the selected _Federated OIDC Sources_, and that their `exp` attribute is not set as now or in the past. -To dynamically limit access based on the claims of the tokens, you can use [Expression policies](../../../customize/policies/expression.mdx), for example: +To dynamically limit access based on the claims of the tokens, you can use [Expression policies](../../../customize/policies/types/expression/index.mdx), for example: ```python return request.context["oauth_jwt"]["iss"] == "https://my.issuer" @@ -138,7 +138,7 @@ Alternatively, you can set the `client_secret` parameter to ``, for ap Input JWTs must be valid access tokens issued by any of the configured _Federated OIDC Providers_, they must not have been revoked and must not have expired. -To dynamically limit access based on the claims of the tokens, you can use [Expression policies](../../../customize/policies/expression.mdx), for example: +To dynamically limit access based on the claims of the tokens, you can use [Expression policies](../../../customize/policies/types/expression/index.mdx), for example: ```python return request.context["oauth_jwt"]["iss"] == "https://my.issuer" diff --git a/website/docs/add-secure-apps/providers/property-mappings/expression.mdx b/website/docs/add-secure-apps/providers/property-mappings/expression.mdx index 1dd6086ed4..fa69782dfb 100644 --- a/website/docs/add-secure-apps/providers/property-mappings/expression.mdx +++ b/website/docs/add-secure-apps/providers/property-mappings/expression.mdx @@ -6,17 +6,17 @@ The property mapping should return a value that is expected by the provider. Sup ## Available Functions -import Functions from "../../../expressions/_functions.mdx"; +import Functions from "../../../expressions/reference/_functions.mdx"; ## Variables -import Objects from "../../../expressions/_objects.md"; +import Objects from "../../../expressions/reference/_objects.md"; -import User from "../../../expressions/_user.md"; +import User from "../../../expressions/reference/_user.md"; diff --git a/website/docs/customize/policies/bindings.md b/website/docs/customize/policies/bindings.md new file mode 100644 index 0000000000..4280a29fc7 --- /dev/null +++ b/website/docs/customize/policies/bindings.md @@ -0,0 +1,112 @@ +--- +title: Policy Bindings and Evaluation +tags: + - policy + - bindings + - access-control +--- + +For step-by-step instructions on creating and attaching policies, see [Working with policies](./working_with_policies.md). This page focuses on where policy bindings apply, how authentik evaluates them, and which options affect the result. + +## Where policies can be bound + +:::info Stage Bindings +In authentik, a stage is attached to a flow through a stage binding. When you attach a policy to a stage inside a flow, you are binding the policy to that stage binding, not directly to the stage definition itself. To learn more, see [Bindings](../../add-secure-apps/bindings-overview/index.md). +::: + +| Binding target | What it controls | How to configure it | +| -------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------- | +| Flow | Whether the user can start or continue using the flow | [Bind a policy to a flow](./working_with_policies.md#bind-a-policy-to-a-flow) | +| Stage binding | Whether a specific stage runs in that flow | [Bind a policy to a stage binding](./working_with_policies.md#bind-a-policy-to-a-stage-binding) | +| Application | Whether the user can access the application | [Bind a policy to an application](./working_with_policies.md#bind-a-policy-to-an-application) | +| Source | Whether the source can be used for login or enrollment | [Bind a policy to a source](./working_with_policies.md#bind-a-policy-to-a-source) | + +In the same binding UI, you can also bind a **user** or **group** directly. Those are evaluated as simple membership checks and are useful when you want a direct allow or deny rule without creating a separate policy object. + +## Validate prompt data with policies + +Some stages also have their own policy hooks. The most common example is the [Prompt stage](../../add-secure-apps/flows-stages/stages/prompt/index.md), which supports **Validation Policies**. + +Use prompt-stage validation policies when the decision depends on data the user has just entered, such as: + +- password complexity +- password history +- matching two prompt fields +- validating an email domain during enrollment + +Prompt-stage validation is often the right place for [Password](./types/password.md), [Password Uniqueness](./types/password-uniqueness.md), and [Expression](./types/expression/index.mdx) policies. + +## How authentik evaluates policies + +When a flow, stage binding, application, or source has multiple bindings, authentik evaluates them in order. + +### Engine mode: `Any` vs `All` + +Every policy binding target has a **Policy engine mode**: + +- `Any`: the target passes when any binding passes +- `All`: the target passes only when every binding passes + +The default mode is `Any`. + +### Order + +Bindings are evaluated in ascending order. This matters most when you inspect logs or when you are combining multiple policies that produce end-user messages. + +### Enabled bindings only + +Disabled bindings are skipped entirely. + +### Direct user and group bindings + +Bindings to users and groups are evaluated alongside policy bindings: + +- a user binding passes when the current user matches +- a group binding passes when the current user is a member of that group + +These are a simple way to mix static membership checks with policy-based logic. + +### No bindings means pass + +If a target has no applicable bindings, authentik treats the result as passing. + +## Binding options + +Bindings have a few important options beyond the target and order. + +### Negate + +**Negate** flips the pass or fail result of the binding. This is useful when you want to express "everyone except this group" or turn an allow-style policy into a deny-style rule without copying it. + +Negation only changes the boolean result. Any messages returned by the policy are left unchanged. + +### Timeout + +**Timeout** limits how long authentik will wait for a policy execution before it is terminated. This is especially relevant for expression policies or other policy types that may call external systems. Defaults to 30 seconds. + +### Failure result + +If a policy errors during execution, **Failure result** decides whether authentik should treat that failure as pass or fail. + +Use this carefully: + +- fail closed when the policy protects access to something sensitive +- fail open only when availability is more important than enforcement for that specific check + +### Execution logging + +Individual policies can enable **Execution logging**. When enabled, authentik logs every execution of that policy, not only failures and exceptions. This is helpful while debugging complex access rules. + +## Common patterns + +### Limit application access with a group or policy + +Bind a group directly when the rule is static. Bind a policy when access depends on runtime context such as network, source, prompt data, or request history. + +### Run a stage only for some users + +Bind a policy to the stage binding, not just to the flow. The stage will only run when that binding passes. + +### Validate user input + +Attach validation policies directly to the prompt stage when the decision depends on the values the user just entered. diff --git a/website/docs/customize/policies/expression.mdx b/website/docs/customize/policies/expression.mdx deleted file mode 100644 index 00d74a10b7..0000000000 --- a/website/docs/customize/policies/expression.mdx +++ /dev/null @@ -1,177 +0,0 @@ ---- -title: Expression Policies ---- - -Expression policies are perhaps the most flexible way to define specific implementations of flows and stages. When you [create](./working_with_policies.md#create-a-policy) an expression policy, you provide your own custom Python code to enforce custom checks and validation. - -Whether the policy passes is determined by the return value of the code: `True` or `False`. - -To pass a policy, use: - -```python -return True -``` - -To fail a policy, use: - -```python -return False -``` - -**Example**: -Here's a simple policy that you could bind to an MFA validation stage if you want only certain users to be prompted for MFA validation: - -``` -if request.context["pending_user"].username == "marie": - return True -return False -``` - -When the policy returns `True`, the MFA validation stage is enforced. When it returns `False`, the MFA validation stage is skipped. - -## Sample expression policies - -Expression policies with sample Python that we have documented: - -- [Source-switching based on email address](./expression/source_switch.md) -- [Managing flow context keys](./expression/managing_flow_context_keys.md) -- [Unique email addresses](./expression/unique_email.md) -- [Create an email address allow list](./expression/whitelist_email.md) - -## Available functions - -### `ak_message(message: str)` - -Add a message, visible by the end user. This can be used to show the reason why they were denied. - -Example: - -```python -ak_message("Access denied") -return False -``` - -import Functions from "../../expressions/_functions.mdx"; - - - -## Variables - -import Objects from "../../expressions/_objects.md"; - - - -- `request`: A PolicyRequest object, which has the following properties: - - `request.user`: The current user, against which the policy is applied. See [User](../../users-sources/user/index.mdx) - - :::caution - When a policy is executed in the context of a flow, this will be set to the user initiating the request, and will only be changed by a `user_login` stage. For that reason, using this value in authentication flow policies may not return the expected user. Use `context['pending_user']` instead; User Identification and other stages update this value during flow execution. - - If the user is not authenticated, this will be set to a user called _AnonymousUser_, which is an instance of [authentik.core.models.User](https://docs.djangoproject.com/en/4.1/ref/contrib/auth/#django.contrib.auth.models.User). - ::: - - - `request.http_request`: The Django HTTP Request. See [Django documentation](https://docs.djangoproject.com/en/4.1/ref/request-response/#httprequest-objects). - - `request.obj`: A Django Model instance. This is only set if the policy is run against an object. - - `request.context`: A dictionary with dynamic data. This depends on the origin of the execution. - -- `geoip`: GeoIP dictionary. The following fields are available: - - :::info - For basic country matching, consider using a [GeoIP policy](./index.md#geoip-policy). - ::: - - `continent`: a two-character continent code like `NA` (North America) or `OC` (Oceania). - - `country`: the two-character [ISO 3166-1](https://en.wikipedia.org/wiki/ISO_3166-1) alpha code for the country. - - `lat`: the approximate latitude of the location associated with the IP address. - - `long`: the approximate longitude of the location associated with the IP address. - - `city`: the name of the city. May be empty. - - ```python - return context["geoip"]["continent"] == "EU" - ``` - -- `asn`: ASN dictionary. The following fields are available: - - :::info - For basic ASN matching, consider using a [GeoIP policy](./index.md#geoip-policy). - ::: - - `asn`: the autonomous system number associated with the IP address. - - `as_org`: the organization associated with the registered autonomous system number for the IP address. - - `network`: the network associated with the record. In particular, this is the largest network where all of the fields except `ip_address` have the same value. - - ```python - return context["asn"]["asn"] == 64496 - ``` - -- `ak_is_sso_flow`: Boolean which is true if request was initiated by authenticating through an external provider. -- `ak_client_ip`: Client's IP Address or 255.255.255.255 if no IP Address could be extracted. Can be [compared](#comparing-ip-addresses), for example - - ```python - return ak_client_ip in ip_network('10.0.0.0/24') - # or - return ak_client_ip.is_private - ``` - - See also [Python documentation](https://docs.python.org/3/library/ipaddress.html#ipaddress.ip_address) - -Additionally, when the policy is executed from a flow, every variable from the flow's current context is accessible under the `context` object. - -This includes the following: - -- `context['flow_plan']`: The actual flow plan itself, can be used to inject stages. - - `context['flow_plan'].context`: The context of the currently active flow, which differs from the policy context. Some fields of flow plan context are passed to the root context, and updated from it, like 'prompt_data', but not every variable - - `context['flow_plan'].context['redirect']`: The URL the user should be redirected to after the flow execution succeeds. (Optional) - -- `context['prompt_data']`: Data which has been saved from a prompt stage or an external source. (Optional) -- `context['application']`: The application the user is in the process of authorizing. (Optional) -- `context['source']`: The source the user is authenticating/enrolling with. (Optional) -- `context['pending_user']`: The currently pending user, see [User](../../users-sources/user/user_ref.mdx) -- `context['is_restored']`: Contains the flow token when the flow plan was restored from a link, for example the user clicked a link to a flow which was sent by an email stage. (Optional) -- `context['auth_method']`: Authentication method (this value is set by password stages) (Optional) - - Depending on method, `context['auth_method_args']` is also set. - - Can be any of: - - `password`: Standard password login - - `auth_mfa`: MFA login (this method is only set if no password was used) - - Sets `context['auth_method_args']` to - - ```json - { - "mfa_devices": [ - { - "pk": 1, - "app": "otp_static", - "name": "Static Token", - "model_name": "staticdevice" - } - ] - } - ``` - - - `auth_webauthn_pwl`: Password-less WebAuthn with Passkeys login - - `jwt`: OAuth Machine-to-machine login via external JWT - - `app_password`: App password (token) - - Sets `context['auth_method_args']` to - - ```json - { - "token": { - "pk": "f6d639aac81940f38dcfdc6e0fe2a786", - "app": "authentik_core", - "name": "test (expires=2021-08-23 15:45:54.725880+00:00)", - "model_name": "token" - } - } - ``` - - - `ldap`: LDAP bind authentication - - Sets `context['auth_method_args']` to - - ```json - { - "source": {} // Information about the source used - } - ``` diff --git a/website/docs/customize/policies/expression/managing_flow_context_keys.md b/website/docs/customize/policies/expression/managing_flow_context_keys.md deleted file mode 100644 index cb797a4c3a..0000000000 --- a/website/docs/customize/policies/expression/managing_flow_context_keys.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Managing flow context keys ---- - -[Flow context](../../../add-secure-apps/flows-stages/flow/context/index.mdx) can be managed in [Expression policies](../expression.mdx) via the `context['flow_plan'].context` variable. - -Here's an example of setting a key in an Expression policy: - -```python -context['flow_plan'].context['redirect_stage_target'] = 'ak-flow://redirected-authentication-flow' -``` - -And here's an example of removing that key: - -```python -context['flow_plan'].context.pop('redirect_stage_target', None) -``` diff --git a/website/docs/customize/policies/expression/source_switch.md b/website/docs/customize/policies/expression/source_switch.md deleted file mode 100644 index 0d3b2ad45c..0000000000 --- a/website/docs/customize/policies/expression/source_switch.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Switch which source is used based on email address ---- - -You can use an expression policy to determine which [source](../../../../users-sources/sources/) (a set of user credentials and data, stored in authentik, Google, GitHub, etc) is used for a particular user, based on the domain of the email address the user enters when they log in and authenticate. - -To switch which source is used for a specific user based on their email domain, create an expression policy and then bind it to the appropriate stage. - -## Create an expression policy - -[Create](../working_with_policies.md#create-a-policy) an expression policy that does the following: - -1. Maps the desired source for each user domain. -2. Determines the user's domain based on their email address. -3. Then "switches" the user to the desired source. - -### Example expression - -```python -# This is a mapping of domains to sources -# the key is a domain for the user and the value is the 'slug' of the source to redirect to -source_email_map = { - "foo.bar.com": "entra-foo", - "bar.baz.com": "entra-bar", -} - -user_email = request.context["pending_user_identifier"] - -_username, _, domain = user_email.partition("@") -source = source_email_map.get(domain) -if not source: - return True -plan = request.context.get("flow_plan") -if not plan: - return False -# For OIDC -# plan.redirect(f"/source/oauth/login/{source}/") -# For SAML -plan.redirect(f"/source/saml/{source}") -return False -``` - -## Bind the policy to the stage - -The new expression policy needs to be bound to the stage binding that comes after the Identification stage (or any custom stage that you might have created). For more information, read our documentation on [bindings](../../../add-secure-apps/bindings-overview/index.md), and for instructions to bind a policy, see [Bind a policy to a stage binding](../../../customize/policies/working_with_policies.md#bind-a-policy-to-a-stage-binding). diff --git a/website/docs/customize/policies/expression/unique_email.md b/website/docs/customize/policies/expression/unique_email.md deleted file mode 100644 index 272d41d111..0000000000 --- a/website/docs/customize/policies/expression/unique_email.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: Ensure unique email addresses ---- - -Due to the database design of authentik, email addresses are by default not required to be unique. However, this behavior can be changed using an expression policy. - -The snippet below can be used in an expression policy within enrollment flows. The policy should be bound to any stage before the [User write](../../../add-secure-apps/flows-stages/stages/user_write.md) stage, or with the [Prompt stage](../../../add-secure-apps/flows-stages/stages/prompt/index.md). - -```python -# Ensure this matches the *Field Key* value of the prompt -field_name = "email" -email = request.context["prompt_data"][field_name] - -pending_user = request.context.get("pending_user") - -from authentik.core.models import User - -query = User.objects.filter(email__iexact=email) - -if pending_user: - query = query.exclude(pk=pending_user.pk) -elif request.user and request.user.is_authenticated: - query = query.exclude(pk=request.user.pk) - -if query.exists(): - ak_message("Email address in use") - return False - -return True -``` diff --git a/website/docs/customize/policies/expression/whitelist_email.md b/website/docs/customize/policies/expression/whitelist_email.md deleted file mode 100644 index 062e37acf7..0000000000 --- a/website/docs/customize/policies/expression/whitelist_email.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: Whitelist email domains ---- - -To add specific email addresses to an allow list for signing in through SSO or directly with default policy customization, follow these steps: - -1. In the authentik Admin interface, navigate to **Customization > Policies** and modify the default policy named `default-source-enrollment-if-sso`. - -2. Add the following code snippet in the policy-specific settings under **Expression** and then click **Update**. - -```python -allowed_domains = ["example.org", "example.net", "example.com"] - -current_domain = request.context["prompt_data"]["email"].split("@")[1] if request.context.get("prompt_data", {}).get("email") else None -if current_domain in allowed_domains: - email = request.context["prompt_data"]["email"] - request.context["prompt_data"]["username"] = email - return ak_is_sso_flow -else: - return ak_message("Enrollment denied for this email domain") -``` - -This configuration specifies the `allowed_domains` list of domains for logging in through SSO, such as Google OAuth2. If your email is not in the available domains, you will receive a 'Permission Denied' message on the login screen. - -You can also enforce your allowed domains policy for authentication by modifying the policy `default-source-authentication-if-sso` with the following expression: - -```python -allowed_domains = ["example.org", "example.net", "example.com"] - -current_domain = request.user.email.split("@")[1] if hasattr(request.user, 'email') and request.user.email else None -if current_domain in allowed_domains: - return ak_is_sso_flow -else: - return ak_message("Authentication denied for this email domain") -``` diff --git a/website/docs/customize/policies/index.md b/website/docs/customize/policies/index.md index 2e95d5ec55..4eb5b4a223 100644 --- a/website/docs/customize/policies/index.md +++ b/website/docs/customize/policies/index.md @@ -1,89 +1,46 @@ --- title: Policies +tags: + - policy + - security + - access-control --- -Policies provide customization and flexibility when defining your users' login and authentication experience. +Policies are reusable checks in authentik. They let you control whether a user can access an application, whether a stage in a flow should run, whether a source can be used, or whether data entered in a prompt stage is valid. -In effect, policies determine whether or not a specific stage is applied to a flow, or whether certain users can even access the flow. +If you are new to policies, start here: -For example, you can create a policy that, for certain users, skips over a stage that prompts for MFA input. Or, you can define a policy that allows users to access a login flow only if the policy criteria are met. See below for other policies, including the reputation policy and an events-driven policy to manage notifications. +- [Working with policies](./working_with_policies.md) shows how to create a policy and bind it to a flow, stage, application, or source. +- [Policy bindings and evaluation](./bindings.md) explains where policies are attached and how authentik combines the results. +- [Types of policies in authentik](./types/index.mdx) groups the built-in policy types by use case. +- [Expression policies](./types/expression/index.mdx) covers Python-based policies for custom logic. -## Create and manage policies +## How policies fit together -For instructions about creating and binding policies to flows and stages, refer to [Working with policies](./working_with_policies.md). +Every policy setup has three parts: -## Standard policies +1. A **policy** defines a single check, such as "is the client in an allowed country?" or "did the user enter an acceptable password?" +2. A **binding** decides where that policy applies, such as a flow, stage binding, application, or source. +3. The **target object** combines all of its bindings using either `Any` or `All` mode. -The following are our standard, out-of-the-box policies that you can [create and customize](./working_with_policies.md) as needed. +You can also bind a **user** or **group** directly in the same places where you bind policies. Those direct bindings are evaluated like simple allow or deny checks and do not require writing a policy. -### Event-matcher policy +## Choose a policy type -This policy is used by the events subsystem. You can use this policy to match events by multiple different criteria, to choose when you get notified. +Use the built-in policy types when they already match what you need. Reach for an expression policy when the built-in types are too limited. -### Expression Policy +| Policy type | Use it when | Notes | +| ----------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| [Event Matcher](./types/event-matcher.md) | You want to react to specific authentik events, usually for notifications or automations. | Matches event action, app, model, and client IP. See [Notifications](../../sys-mgmt/events/notifications.md). | +| [Expression](./types/expression/index.mdx) | You need custom logic that is not covered by a more specialized policy type. | Most flexible option. Runs Python and can inspect flow context, prompt data, user data, request metadata, and more. | +| [GeoIP](./types/geoip.md) | You want to allow or deny requests based on country, ASN, or travel patterns. | Can also check recent login distance and impossible-travel scenarios. | +| [Password](./types/password.md) | You want to validate password complexity, HIBP exposure, or zxcvbn strength. | Commonly attached to a prompt stage's **Validation Policies**. | +| [Password Expiry](./types/password-expiry.md) | You want to expire passwords after a fixed number of days. | Can either deny login or mark the password unusable so the user must update it. | +| [Password Uniqueness](./types/password-uniqueness.md) | You want to prevent password reuse. | Enterprise feature. | +| [Reputation](./types/reputation.md) | You want to react to failed logins or suspicious sign-in activity. | Useful for showing CAPTCHA or another challenge only to low-reputation requests. | -See [Expression Policy](./expression.mdx). +## Deprecated policy types -### GeoIP policy +### Have I Been Pwned policy -Use this policy for simple GeoIP lookups, such as country or ASN matching. (For a more advanced GeoIP lookup, use an [Expression policy](./expression.mdx).) - -With the GeoIP policy, you can use the **Distance Settings** options to set travel "expectations" and control login attempts based on GeoIP location. The GeoIP policy calculates the values defined for travel distances (in kilometers), and then either passes or fails based on the results. If the GeoIP policy fails, the current login attempt is not allowed. - - - **Maximum distance**: define the allowed maximum distance between a login's initial GeoIP location and the GeoIP location of a subsequent login attempt. - - - **Distance tolerance**: optionally, add an additional "tolerance" distance. This value is added to the **Maximum distance** value, then the total is used in the calculations that determine if the policy fails or passes. - - - **Historical Login Count**: define the number of login events that you want to use for the distance calculations. For example, with the default value of 5, the policy will check the distance between each of the past 5 login attempts, and if any of those distances exceed the **Maximum distance** PLUS the **Distance tolerance**, then the policy will fail and the current login attempt will not be allowed. - - - **Check impossible travel**: this option, when enabled, provides an additional layer of calculations to the policy. With Impossible travel, a built-in value of 1,000 kilometers is used as the base distance. This distance, PLUS the value defined for **Impossible travel tolerance**, is the maximum allowed distance for the policy to pass. Note that the value defined in **Historical Login Count** (the number of login events to check) is also used for Impossible travel calculations. - - - **Impossible travel tolerance**: optionally, you can add an additional "tolerance" distance. This value is added to the built-in allowance of 1000 kilometers per hour, then the total is used in the calculations that run against each of the login events (to determine if the travel would have been possible in the amount of time since the previous login event) to determine if the policy fails or passes. - -:::info -GeoIP is included in every release of authentik and does not require any additional setup for creating GeoIP policies. For information about advanced uses (configuring your own database, etc.) and system management of GeoIP data, refer to our [GeoIP documentation](../../sys-mgmt/ops/geoip.mdx). -::: - -### Password-Expiry Policy - -This policy can enforce regular password rotation by expiring set passwords after a finite amount of time. This forces users to set a new password. - -### Password Policy - -:::warning -By default, authentik's Password policy is compliant with [NIST's recommendations](https://pages.nist.gov/800-63-4/sp800-63b.html#password) for passwords. To remain compliant with NIST, be cautious when editing the default values. For additional hardening configuration settings, refer to [Hardening authentik](../../security/security-hardening.md#password-policy). -::: - -This policy allows you to specify password rules, such as length and required characters. -The following rules can be set: - -- Minimum number of uppercase characters. -- Minimum number of lowercase characters. -- Minimum number of symbol characters. -- Minimum length. -- Symbol charset (define which characters are counted as symbols). - -The following checks can also be done with this policy: - -- Check the password hash against the database of [Have I Been Pwned](https://haveibeenpwned.com/). Only the first 5 characters of the hashed password are transmitted, the rest is compared in authentik. -- Check the password against the password complexity checker [zxcvbn](https://github.com/dropbox/zxcvbn), which detects weak passwords on various metrics. - -### Password Uniqueness Policy - -This policy prevents users from reusing their previous passwords when setting a new password. For detailed information, see [Password Uniqueness Policy](./unique_password.md). - -### Reputation Policy - -authentik keeps track of recent login attempts per [Identifier](../../add-secure-apps/flows-stages/stages/identification/#user-fields) and client IP. These values are saved as scores. Failed logins decrease the score by 1, while successful logins increase the score by 1. - -This policy can be used, for example, to prompt clients with a low score to pass a CAPTCHA test before they can continue. - -To make sure this policy is executed correctly, set _Evaluate when stage is run_ when using it with a flow. - -### Have I Been Pwned Policy - -:::info -This policy is deprecated since authentik 2022.11.0, as this can be done with the password policy now. -::: - -This policy checks the hashed password against the [Have I Been Pwned](https://haveibeenpwned.com/) API. This only sends the first 5 characters of the hashed password. The remaining comparison is done within authentik. +The standalone Have I Been Pwned policy is deprecated. Use the [Password Policy](./types/password.md) instead, which includes the same HIBP check. diff --git a/website/docs/customize/policies/types/event-matcher.md b/website/docs/customize/policies/types/event-matcher.md new file mode 100644 index 0000000000..3bb9d128a5 --- /dev/null +++ b/website/docs/customize/policies/types/event-matcher.md @@ -0,0 +1,55 @@ +--- +title: Event Matcher Policy +tags: + - policy + - events + - notifications +--- + +Use an Event Matcher policy when you want to match authentik events against a small set of built-in fields instead of writing a custom expression. + +This policy is most commonly used with [Notification Rules](../../../sys-mgmt/events/notifications.md). + +## When to use it + +Use an Event Matcher policy when you want to match against events such as: + +- a failed login +- a model being created, updated, or deleted +- activity from a specific authentik app +- activity from a specific client IP + +For more complex matching, such as network ranges or logic across multiple event fields, use an [Expression policy](./expression/index.mdx) instead. + +## What it matches + +An Event Matcher policy can match on: + +- action +- app +- model +- exact client IP + +Any field you leave empty is treated as a wildcard. Any field you configure must match for the policy to pass. + +:::info Event Context +This policy is useful only when an event object is present in the policy context, such as when a notification rule evaluates an event. +::: + +## Create an Event Matcher policy + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Customization** > **Policies**. +3. Click **New Policy** and select **Event Matcher Policy**. +4. Configure the fields you want to match. +5. Click **Create Policy**. + +## Send notifications about an event match + +To send notifications for a subset of authentik events: + +1. Create an Event Matcher policy. +2. Create or edit a [Notification Rule](../../../sys-mgmt/events/notifications.md). +3. Bind the policy to that notification rule. + +Be aware that an event has to match all configured fields in the policy, otherwise the notification rule will not trigger. diff --git a/website/docs/customize/policies/types/expression/index.mdx b/website/docs/customize/policies/types/expression/index.mdx new file mode 100644 index 0000000000..7a9f8f5bd6 --- /dev/null +++ b/website/docs/customize/policies/types/expression/index.mdx @@ -0,0 +1,143 @@ +--- +title: Expression Policies +tags: + - policy + - expression + - python +--- + +Expression policies let you write custom Python for cases where the built-in policy types are not enough. + +They are commonly used to: + +- branch or redirect inside authentication flows +- validate prompt data +- enforce organization-specific access rules +- make decisions based on request metadata, GeoIP, ASN, or flow context + +For general policy concepts such as bindings, ordering, `Any` vs `All`, and where policies are attached, see [Policy bindings and evaluation](../../bindings.md). + +:::warning Privileged Feature +Expression policies execute server-side Python inside authentik. Treat the ability to create or edit them as a highly privileged permission. +::: + +## Start here + +- [Expression reference](./reference.mdx) covers return values, helper functions, variables, and flow context. +- [Managing flow context keys](./managing_flow_context_keys.md) shows how to change flow behavior. +- [Switch which source is used based on email address](./source_switch.md) shows a common routing pattern. +- [Ensure unique email addresses](./unique_email.md) and [Allow only specific email domains](./whitelist_email.md) cover prompt-data validation. + +## A simple example + +The following expression causes an MFA validation stage to run only for one specific user: + +```python +if request.context["pending_user"].username == "marie": + return True +return False +``` + +When the policy is bound to the stage binding, the stage runs only when the expression passes. + +To understand what values are available in the expression environment, see [Expression reference](./reference.mdx). + +## Common pitfalls + +### Use `context['pending_user']` inside flows + +When a policy runs during a flow, `request.user` is not always the user who is currently being authenticated. Until a login or user-writing stage updates the active user, `request.user` may still be `AnonymousUser` or the previously authenticated user. + +Inside authentication and enrollment flows, prefer: + +```python +pending_user = request.context.get("pending_user") +``` + +instead of relying on `request.user`. + +### Prompt data lives in `context['prompt_data']` + +If you are validating values entered in a [Prompt stage](../../../../add-secure-apps/flows-stages/stages/prompt/index.md), read them from `context["prompt_data"]`: + +```python +email = context["prompt_data"]["email"] +``` + +### Flow state can be changed through `flow_plan` + +When an expression runs inside a flow, you can inspect and update flow state through `context["flow_plan"]` and `context["flow_plan"].context`. This is powerful, but it also means your expression can change how the rest of the flow behaves. + +For examples, see [Managing flow context keys](./managing_flow_context_keys.md) and [Switch which source is used based on email address](./source_switch.md). + +## Sample expression policies + +The following examples document common uses: + +- [Switch which source is used based on email address](./source_switch.md) +- [Managing flow context keys](./managing_flow_context_keys.md) +- [Ensure unique email addresses](./unique_email.md) +- [Allow only specific email domains](./whitelist_email.md) + +### `auth_method` and `auth_method_args` + +Depending on the flow, `context["auth_method_args"]` may also be populated. + +Some fields from the flow-plan context are mirrored into the root policy context and updated from it, such as `prompt_data`, but not every flow-plan key is copied that way. + +Common `auth_method` values include: + +- `password`: standard password login +- `auth_mfa`: MFA login without a password step +- `auth_webauthn_pwl`: passwordless WebAuthn or passkey login +- `token`: token-based authentication, such as an app password +- `jwt`: machine-to-machine login through an external JWT +- `ldap`: LDAP bind authentication + +For some authentication methods, `context["auth_method_args"]` contains additional structured data. + +For `auth_mfa`, `context["auth_method_args"]` is shaped like: + +```json +{ + "mfa_devices": [ + { + "pk": 1, + "app": "otp_static", + "name": "Static Token", + "model_name": "staticdevice" + } + ] +} +``` + +For `token`, `context["auth_method_args"]` depends on the code path. It may contain a token object: + +```json +{ + "token": { + "pk": "f6d639aac81940f38dcfdc6e0fe2a786", + "app": "authentik_core", + "name": "test (expires=2021-08-23 15:45:54.725880+00:00)", + "model_name": "token" + } +} +``` + +or a token identifier: + +```json +{ + "identifier": "service-account-token" +} +``` + +For `ldap`, `context["auth_method_args"]` contains information about the source used: + +```json +{ + "source": {} +} +``` + +For simple country or ASN checks, a [GeoIP policy](../geoip.md) is usually easier to manage than a custom expression. For flow manipulation, see the example pages above. diff --git a/website/docs/customize/policies/types/expression/managing_flow_context_keys.md b/website/docs/customize/policies/types/expression/managing_flow_context_keys.md new file mode 100644 index 0000000000..70a82c5b38 --- /dev/null +++ b/website/docs/customize/policies/types/expression/managing_flow_context_keys.md @@ -0,0 +1,29 @@ +--- +title: Managing flow context keys +tags: + - policy + - expression + - flows +--- + +[Flow context](../../../../add-secure-apps/flows-stages/flow/context/index.mdx) can be read and updated from an [Expression policy](./index.mdx) through `context["flow_plan"].context`. + +This is useful when you want to influence later stages in the same flow, such as changing a redirect target or passing data to another stage. + +For `redirect_stage_target`, use the format `ak-flow://{slug}` when you want the [Redirect stage](../../../../add-secure-apps/flows-stages/stages/redirect/index.md) to redirect to another flow. See [`redirect_stage_target`](../../../../add-secure-apps/flows-stages/flow/context/index.mdx#redirect_stage_target-string) for the full behavior. + +## Set a flow-context key + +```python +context["flow_plan"].context["redirect_stage_target"] = "ak-flow://redirected-authentication-flow" +return True +``` + +## Remove a flow-context key + +```python +context["flow_plan"].context.pop("redirect_stage_target", None) +return True +``` + +Be careful when modifying flow context in widely reused policies, because the change affects the active flow plan, not only the policy itself. diff --git a/website/docs/customize/policies/types/expression/reference.mdx b/website/docs/customize/policies/types/expression/reference.mdx new file mode 100644 index 0000000000..f56ea0a5bb --- /dev/null +++ b/website/docs/customize/policies/types/expression/reference.mdx @@ -0,0 +1,152 @@ +--- +title: Expression Reference +tags: + - policy + - expression + - python + - reference +--- + +import Functions from "../../../../expressions/reference/_functions.mdx"; +import Objects from "../../../../expressions/reference/_objects.md"; + +This page documents the expression policy execution environment in authentik. + +## Return values + +An expression policy passes when it returns `True` and fails when it returns `False`. + +```python +return True +``` + +```python +return False +``` + +## Available helper functions + +### `ak_message(message: str)` + +Add a user-visible message to the current policy result. + +```python +ak_message("Access denied") +return False +``` + + + +## Available variables and objects + + + +## Expression-specific context + +The imported object reference above covers the generic expression environment. The values below are the ones that are most specific to expression policies in authentik. + +### `request` + +`request` is a policy request object with the following properties: + +- `request.user`: the current user against which the policy is being evaluated. See [User](../../../../users-sources/user/index.mdx). +- `request.http_request`: the Django HTTP request, when one exists. See the [Django request documentation](https://docs.djangoproject.com/en/4.1/ref/request-response/#httprequest-objects). +- `request.obj`: the object the policy is being evaluated against +- `request.context`: a dictionary with dynamic data for the current execution + +:::caution Flow User Context +When an expression policy runs inside a flow, `request.user` is not always the user who is currently being authenticated. Until a `user_login` stage updates the active user, this may still be `AnonymousUser` or another previously authenticated user. + +In authentication and enrollment flows, use `context["pending_user"]` when you want the user currently being identified or enrolled. + +If the user is not authenticated, `request.user` will be `AnonymousUser`, which is still an instance of [authentik.core.models.User](https://docs.djangoproject.com/en/4.1/ref/contrib/auth/#django.contrib.auth.models.User). +::: + +### Common flow-related values + +The most commonly used values in flow-related expressions are: + +- `context["pending_user"]`: the user currently being identified or enrolled in a flow +- `context["prompt_data"]`: data collected from a prompt stage +- `context["application"]`: the application involved in the current authorization flow +- `context["source"]`: the source involved in the current login or enrollment +- `context["flow_plan"]`: the active flow plan and its mutable context +- `context["geoip"]` and `context["asn"]`: GeoIP and ASN lookups for the client IP +- `ak_client_ip`: the parsed client IP address object +- `ak_is_sso_flow`: whether the current flow was initiated by an external identity provider source + +### `geoip` + +`context["geoip"]` contains GeoIP information for the client IP. + +Available fields include: + +- `continent`: a two-character continent code such as `NA` or `EU` +- `country`: the two-character [ISO 3166-1](https://en.wikipedia.org/wiki/ISO_3166-1) alpha code +- `lat`: approximate latitude +- `long`: approximate longitude +- `city`: city name, when available + +```python +return context["geoip"]["continent"] == "EU" +``` + +:::info Prefer GeoIP Policy +For simple country matching, prefer a [GeoIP policy](../geoip.md). +::: + +### `asn` + +`context["asn"]` contains autonomous system information for the client IP. + +Available fields include: + +- `asn`: the autonomous system number +- `as_org`: the organization name for that ASN +- `network`: the matching network + +```python +return context["asn"]["asn"] == 6939 +``` + +:::info Prefer GeoIP Policy +For simple ASN matching, prefer a [GeoIP policy](../geoip.md). +::: + +### `ak_client_ip` + +`ak_client_ip` is the parsed client IP address object. You can compare it with [Python's `ipaddress` helpers](https://docs.python.org/3/library/ipaddress.html#ipaddress.ip_address): + +```python +from ipaddress import ip_network + +return ak_client_ip in ip_network("10.0.0.0/24") +``` + +You can also inspect properties on the parsed IP object, for example: + +```python +return ak_client_ip.is_private +``` + +`ak_client_ip.is_private` follows Python's `ipaddress` semantics and returns `True` for addresses that are not globally reachable, not only for RFC1918 private ranges. + +### `ak_is_sso_flow` + +`ak_is_sso_flow` is `True` when the current flow was initiated by an external identity provider source. + +## Flow context keys + +When the policy runs inside a flow, authentik exposes the current flow context under `context`. + +Common keys include: + +- `context["flow_plan"]`: the active flow plan +- `context["flow_plan"].context`: the mutable flow-plan context +- `context["flow_plan"].context["redirect"]`: the post-flow redirect URL, when set +- `context["prompt_data"]`: data collected from prompt stages or external sources +- `context["application"]`: the application being authorized +- `context["source"]`: the source being used for authentication or enrollment +- `context["pending_user"]`: the user currently being identified or enrolled +- `context["is_restored"]`: the flow token when the flow was restored from a link +- `context["auth_method"]`: the authentication method recorded by the flow diff --git a/website/docs/customize/policies/types/expression/source_switch.md b/website/docs/customize/policies/types/expression/source_switch.md new file mode 100644 index 0000000000..beae2e246a --- /dev/null +++ b/website/docs/customize/policies/types/expression/source_switch.md @@ -0,0 +1,60 @@ +--- +title: Switch which source is used based on email address +tags: + - policy + - expression + - sources +--- + +You can use an [expression policy](./index.mdx) to route users to different [sources](../../../../../users-sources/sources/) based on the email address they enter. + +This is useful when different email domains should authenticate against different upstream identity providers. + +## Create the policy + +[Create an expression policy](../../working_with_policies.md#create-a-policy) that: + +1. maps email domains to source slugs +2. reads the identifier collected earlier in the flow +3. redirects the user to the matching source when a mapping exists + +## Where to bind it + +Bind the expression to the stage binding immediately after the [Identification stage](../../../../add-secure-apps/flows-stages/stages/identification/index.mdx), or after whichever stage first collects the identifier you want to inspect. + +For more background on binding policies to stages, see [Working with policies](../../working_with_policies.md#bind-a-policy-to-a-stage-binding). + +## Example expression + +```python +# Map email domains to source slugs. +source_email_map = { + "foo.bar.com": "entra-foo", + "bar.baz.com": "entra-bar", +} + +user_email = request.context["pending_user_identifier"] + +_username, _, domain = user_email.partition("@") +source = source_email_map.get(domain) +if not source: + return True + +plan = request.context.get("flow_plan") +if not plan: + return False + +# For OIDC +# plan.redirect(f"/source/oauth/login/{source}/") +# For SAML +plan.redirect(f"/source/saml/{source}") +return False +``` + +## How it works + +- The policy reads `pending_user_identifier`, which is the identifier gathered earlier in the flow. +- If the email domain is not in the mapping, the policy returns `True` and flow execution continues normally. +- If the domain maps to a source, the policy redirects the flow and returns `False` so the current path does not continue. + +Adjust the redirect path for the source type you use. The example above includes both OIDC and SAML patterns. diff --git a/website/docs/customize/policies/types/expression/unique_email.md b/website/docs/customize/policies/types/expression/unique_email.md new file mode 100644 index 0000000000..63d59e3d00 --- /dev/null +++ b/website/docs/customize/policies/types/expression/unique_email.md @@ -0,0 +1,35 @@ +--- +title: Ensure unique email addresses +tags: + - policy + - expression + - email +--- + +By default, authentik does not require email addresses to be unique. If you want to enforce uniqueness, use an [expression policy](./index.mdx) during enrollment or profile-edit flows. + +Bind the policy before the [User write stage](../../../../add-secure-apps/flows-stages/stages/user_write.md), or attach it directly to the [Prompt stage](../../../../add-secure-apps/flows-stages/stages/prompt/index.md) that collects the email address. + +## Example expression + +In this example, `email` must match the field key from your prompt stage. The `pending_user` exclusion lets the same policy work for updates as well as new users. + +```python +# Ensure this matches the *Field Key* value of the prompt +field_name = "email" +email = request.context["prompt_data"][field_name] +pending_user = request.context.get("pending_user") + +from authentik.core.models import User +query = User.objects.filter(email__iexact=email) +if pending_user: + query = query.exclude(pk=pending_user.pk) +elif request.user and request.user.is_authenticated: + query = query.exclude(pk=request.user.pk) + +if query.exists(): + ak_message("Email address in use") + return False + +return True +``` diff --git a/website/docs/customize/policies/types/expression/whitelist_email.md b/website/docs/customize/policies/types/expression/whitelist_email.md new file mode 100644 index 0000000000..305fd56bb1 --- /dev/null +++ b/website/docs/customize/policies/types/expression/whitelist_email.md @@ -0,0 +1,68 @@ +--- +title: Allow only specific email domains +tags: + - policy + - expression + - email +--- + +Use an [expression policy](./index.mdx) when only specific email domains should be allowed to enroll or authenticate. + +The examples below work well with source-related enrollment and authentication flows. + +## Restrict enrollment by domain + +To update an existing source-enrollment policy: + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Customization** > **Policies**. +3. Open the policy used for source enrollment, such as `default-source-enrollment-if-sso`. +4. Replace the expression body with logic like the example below. +5. Save the policy. + +Edit the policy used for source enrollment, such as `default-source-enrollment-if-sso`, and use an expression like this: + +```python +allowed_domains = ["example.org", "example.net", "example.com"] + +current_domain = request.context["prompt_data"]["email"].split("@")[1] if request.context.get("prompt_data", {}).get("email") else None +if current_domain in allowed_domains: + email = request.context["prompt_data"]["email"] + request.context["prompt_data"]["username"] = email + return ak_is_sso_flow +else: + ak_message("Enrollment denied for this email domain") + return False +``` + +This expression: + +- checks the submitted email address +- allows only the domains in `allowed_domains` +- copies the email address into `username` for the rest of the flow +- shows a user-visible error when enrollment is denied + +## Restrict authentication by domain + +To enforce the same rule for authentication: + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Customization** > **Policies**. +3. Open the source-authentication policy, such as `default-source-authentication-if-sso`. +4. Update the expression with logic like the example below. +5. Save the policy. + +To enforce the same rule during authentication, edit the source-authentication policy, such as `default-source-authentication-if-sso`, and use: + +```python +allowed_domains = ["example.org", "example.net", "example.com"] + +current_domain = request.user.email.split("@")[1] if hasattr(request.user, 'email') and request.user.email else None +if current_domain in allowed_domains: + return ak_is_sso_flow +else: + ak_message("Authentication denied for this email domain") + return False +``` + +If you use different flows or policy names, adapt the example to the policy that already governs enrollment or authentication for that source. diff --git a/website/docs/customize/policies/types/geoip.md b/website/docs/customize/policies/types/geoip.md new file mode 100644 index 0000000000..1b2222017d --- /dev/null +++ b/website/docs/customize/policies/types/geoip.md @@ -0,0 +1,61 @@ +--- +title: GeoIP Policy +tags: + - policy + - geoip + - security +--- + +Use a GeoIP policy when you want to make access decisions based on where a request appears to come from. + +For simple country or ASN matching, a GeoIP policy is usually easier to maintain than an [Expression policy](./expression/index.mdx). + +## What it can do + +A GeoIP policy can: + +- allow or deny requests by country +- allow or deny requests by ASN +- compare the current login location to recent login events +- detect impossible travel patterns + +:::info GeoIP Data +GeoIP support is included in authentik. For advanced setup and database management, see [GeoIP operations](../../../sys-mgmt/ops/geoip.mdx). +::: + +## Country and ASN matching + +Use the country and ASN fields when you want straightforward allow or deny logic based on: + +- the client's country +- the client's autonomous system number + +If either country or ASN matching is configured, the static part of the policy passes when any configured country or ASN match succeeds. + +## Distance settings + +GeoIP policies can also compare the current login against recent login history. + +When distance checks are enabled, authentik evaluates the current login against the configured number of historical login events. If any comparison exceeds the allowed distance or fails the impossible-travel check, the policy fails. + +- **Maximum distance**: the maximum allowed distance between a previous login location and the current login location. +- **Distance tolerance**: an additional tolerance, in kilometers, added to the maximum distance before the policy fails. +- **Historical Login Count**: how many recent login events authentik should compare against. +- **Check impossible travel**: enables an additional check based on travel speed between recent login events. +- **Impossible travel tolerance**: an additional tolerance, in kilometers, added to the built-in impossible-travel allowance. + +## Create a GeoIP policy + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Customization** > **Policies**. +3. Click **New Policy** and select **GeoIP Policy**. +4. Configure the country, ASN, and optional distance settings you need. +5. Click **Create Policy**. + +## Common use + +GeoIP policies are often bound to: + +- applications, to restrict access by network geography +- stage bindings, to trigger additional checks only for risky requests +- flows, when access to the whole flow should depend on request origin diff --git a/website/docs/customize/policies/types/index.mdx b/website/docs/customize/policies/types/index.mdx new file mode 100644 index 0000000000..42329c9be5 --- /dev/null +++ b/website/docs/customize/policies/types/index.mdx @@ -0,0 +1,15 @@ +--- +title: Types of policies in authentik +tags: + - policy + - reference + - security +--- + +import DocCardList from "@theme/DocCardList"; + +These pages describe the built-in policy objects you can create in authentik. + +Use this section to browse the dedicated reference page for each policy type. + + diff --git a/website/docs/customize/policies/types/password-expiry.md b/website/docs/customize/policies/types/password-expiry.md new file mode 100644 index 0000000000..4e5fb6b9b2 --- /dev/null +++ b/website/docs/customize/policies/types/password-expiry.md @@ -0,0 +1,37 @@ +--- +title: Password Expiry Policy +tags: + - policy + - password + - security +--- + +Use a Password Expiry policy when passwords should expire after a fixed number of days. + +## How it works + +This policy checks how many days have passed since the user's password was last changed. + +When the configured limit is exceeded, the policy fails. Depending on the policy settings, authentik can either: + +- deny access with an expiry message +- mark the password unusable so the user must set a new one + +## Key setting + +- **Days**: how old a password may be before the policy fails +- **Deny only**: if enabled, the policy only fails; if disabled, authentik can also mark the password unusable + +## Create a Password Expiry policy + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Customization** > **Policies**. +3. Click **New Policy** and select **Password Expiry Policy**. +4. Configure the allowed password age and whether the policy should run in deny-only mode. +5. Click **Create Policy**. + +## Common use + +Password Expiry policies are usually used together with a password change or recovery flow so users have a clear path to set a new password after expiry. + +If you also need password-history enforcement, combine this policy with [Password Uniqueness Policy](./password-uniqueness.md). diff --git a/website/docs/customize/policies/types/password-uniqueness.md b/website/docs/customize/policies/types/password-uniqueness.md new file mode 100644 index 0000000000..d8fa0462ed --- /dev/null +++ b/website/docs/customize/policies/types/password-uniqueness.md @@ -0,0 +1,74 @@ +--- +title: Password Uniqueness Policy +sidebar_label: Password Uniqueness Policy +tags: + - policy + - password + - security + - enterprise +authentik_version: "2025.4.0" +authentik_enterprise: true +--- + +The Password Uniqueness policy is an enterprise policy that prevents users from reusing previously used passwords. + +In most deployments, you attach it to a [Prompt stage](../../../add-secure-apps/flows-stages/stages/prompt/index.md) through that stage's **Validation Policies** so authentik can validate the new password at the moment it is entered. + +## How it works + +This policy stores a history of previous password hashes for each user. When a new password is submitted, authentik compares it against the most recent password-history entries configured in the policy. + +If the new password matches one of those historical entries, the policy fails and the user must choose a different password. + +Password history is maintained automatically while the policy is in use. + +:::info Password History Start +This policy only starts building password history once it is in use. The first password change after you enable it seeds the history; there is no older password history to compare against before that point. +::: + +## When to use it + +Use Password Uniqueness when you need password-history enforcement, such as: + +- security baselines that forbid password reuse +- password rotation requirements +- compliance frameworks that require password history checks + +For broader password controls, combine it with: + +- [Password Policy](./password.md) for complexity, HIBP, and zxcvbn checks +- [Password Expiry Policy](./password-expiry.md) if you also require password rotation + +## Create the policy + +To create a Password Uniqueness policy: + +1. In the Admin interface, navigate to **Customization** > **Policies**. +2. Click **New Policy** to define a new Password Uniqueness Policy. +3. Configure the policy: + - **Name**: use a descriptive name. + - **Password field**: enter the field key that contains the new password. In the default flows this is usually `password`. + - **Number of previous passwords to check**: choose how many previous passwords authentik should compare against and retain for future checks. +4. Click **Create Policy**. + +## Attach the policy to password entry + +In most cases, bind the policy to the prompt stage where the user enters the new password. + +For example, if you use the `default-password-change` flow: + +1. Open the `default-password-change-prompt` stage. +2. In **Validation Policies**, add your Password Uniqueness policy. +3. Save the stage. + +This is the recommended placement because the policy needs access to the password field in prompt data. If you bind the policy somewhere else, that password field must still be present in the policy context. + +:::info Storage Model +Password history records are stored securely and cannot be used to reconstruct original passwords. +::: + +## Configuration tips + +- The **Password field** must match the prompt field's **Field key** exactly. +- If you have multiple password-entry prompts, point the policy at the field that represents the new password. +- Increase the history count only as far as your requirements need. Higher values mean more password history is retained per user. diff --git a/website/docs/customize/policies/types/password.md b/website/docs/customize/policies/types/password.md new file mode 100644 index 0000000000..62695dbd64 --- /dev/null +++ b/website/docs/customize/policies/types/password.md @@ -0,0 +1,57 @@ +--- +title: Password Policy +tags: + - policy + - password + - security +--- + +Use a Password policy when you want to validate a password entered in a prompt stage. + +This policy is most often attached to a [Prompt stage](../../../add-secure-apps/flows-stages/stages/prompt/index.md) through that stage's **Validation Policies**. + +## What it can enforce + +A Password policy can enforce: + +- minimum length +- minimum counts for uppercase, lowercase, digits, and symbols +- a custom symbol set +- [Have I Been Pwned](https://haveibeenpwned.com/) exposure checks +- [zxcvbn](https://github.com/dropbox/zxcvbn) strength checks + +The policy reads the configured password field from prompt data, so the field key in the policy must match the password field used by your prompt stage. + +:::warning Password Guidance +By default, authentik's Password policy aligns with [NIST password guidance](https://pages.nist.gov/800-63-4/sp800-63b.html#password). Be careful when tightening or weakening those defaults. For broader guidance, see [Hardening authentik](../../../security/security-hardening.md#password-policy). +::: + +## Have I Been Pwned checks + +When the HIBP check is enabled, authentik compares the password hash against the Have I Been Pwned password database. + +Only the first 5 characters of the SHA-1 hash are sent to the API. The remaining comparison is done in authentik. + +## zxcvbn checks + +When the zxcvbn check is enabled, authentik evaluates password strength and can reject passwords that are still weak even if they satisfy simple character-count rules. + +## Create a Password policy + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Customization** > **Policies**. +3. Click **New Policy** and select **Password Policy**. +4. Configure the password field and validation rules you want to enforce. +5. Click **Create Policy**. + +## Attach it to password entry + +In most cases, bind the policy to the prompt stage where the user enters a new password. + +This is commonly used in: + +- enrollment flows +- password reset flows +- password change flows + +If you also want to prevent password reuse, combine this policy with [Password Uniqueness Policy](./password-uniqueness.md). diff --git a/website/docs/customize/policies/types/reputation.md b/website/docs/customize/policies/types/reputation.md new file mode 100644 index 0000000000..e6d42eef6c --- /dev/null +++ b/website/docs/customize/policies/types/reputation.md @@ -0,0 +1,48 @@ +--- +title: Reputation Policy +tags: + - policy + - reputation + - security +--- + +Use a Reputation policy when you want authentik to react to repeated failed authentication attempts from a username, a client IP, or both. + +## How reputation works + +authentik tracks a reputation score over time: + +- failed logins decrease the score +- successful logins increase the score + +The policy passes when the score is at or below the configured threshold. + +In practice, this is usually used to show an extra challenge only when a request looks risky. For example, you can bind a CAPTCHA stage so it runs only for low-reputation requests. + +## What it can check + +A Reputation policy can evaluate: + +- the client IP +- the username +- both together + +The threshold defaults to a low score, so the policy is naturally suited to "trigger extra verification when trust is low" scenarios. + +## Create a Reputation policy + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Customization** > **Policies**. +3. Click **New Policy** and select **Reputation Policy**. +4. Choose whether to check IP, username, or both, and set the threshold. +5. Click **Create Policy**. + +## Use it on stage bindings + +When you use a Reputation policy on a flow stage binding, configure the stage binding to **Evaluate when stage is run** so authentik can use the latest request context. + +This is especially important when the policy should react to the current login attempt rather than only to the initial planned flow state. + +## Related settings + +System-wide reputation limits and expiry are documented in [Settings](../../../sys-mgmt/settings.md). diff --git a/website/docs/customize/policies/unique_password.md b/website/docs/customize/policies/unique_password.md deleted file mode 100644 index 26570cfacc..0000000000 --- a/website/docs/customize/policies/unique_password.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Password Uniqueness Policy -sidebar_label: Password Uniqueness Policy -tags: - - policy - - password - - security - - enterprise -authentik_version: "2025.4.0" -authentik_enterprise: true ---- - -The Password Uniqueness policy prevents users from reusing their previous passwords when setting a new password. To use this feature, you will need to create a Password Uniqueness policy, using the instructions below. - -## How it works - -This policy maintains a record of previously used passwords for each user. When a new password is created, it is compared against this historical log. If a match is found with any previous password, the policy is not met, and the user is required to choose a different password. - -The password history is maintained automatically when this policy is in use. Old password hashes are stored securely in authentik's database. - -:::info -This policy takes effect after the first password change following policy activation. Before that first change, there's no password history data to compare against. -::: - -## Integration with other policies - -For comprehensive password security, consider using this policy alongside: - -- [Password Policy](./index.md#password-policy) - To enforce password complexity rules -- [Password-Expiry Policy](./index.md#password-expiry-policy) - To enforce regular password rotation - -## Implement a Password Uniqueness policy - -To implement a policy that prevents users from reusing their previous passwords, follow these steps: - -1. In the Admin interface, navigate to **Customization** > **Policies**. -2. Click **Create** to define a new Password Uniqueness Policy. - - **Name**: provide a descriptive name for the policy. - - **Password field**: enter the name of the input field to check for the new password. By default, if no custom flows are used, the field name is `password`. This field name must match the field name used in your Prompt stage. - - **Number of previous passwords to check**: enter the number of past passwords that you want to set as the number of previous passwords that are checked and stored for each user, with a default of 1. For instance, if set to 3, users will not be able to reuse any of their last 3 passwords. -3. Bind the policy to your **password prompt stage**: For example, if you're using the `default-password-change` flow, edit the `default-password-change-prompt` stage and add the policy in the **Validation Policies** section. - -:::info -Password history records are stored securely and cannot be used to reconstruct original passwords. -::: diff --git a/website/docs/customize/policies/working_with_policies.md b/website/docs/customize/policies/working_with_policies.md index eacb6f662b..f21bcae5bf 100644 --- a/website/docs/customize/policies/working_with_policies.md +++ b/website/docs/customize/policies/working_with_policies.md @@ -1,32 +1,40 @@ --- title: Working with policies +tags: + - policy + - access-control + - how-to --- For an overview of policies, refer to our documentation on [Policies](./index.md). -authentik provides several [standard policy types](./index.md#standard-policies), which can be configured for your specific needs. We also document several useful [expression policies](./expression.mdx#sample-expression-policies). +authentik provides several [built-in policy types](./types/index.mdx), which can be configured for your specific needs. We also document several useful [expression policy examples](./types/expression/index.mdx#sample-expression-policies). :::info -You can add expressions to our standard policies to further customize them. +You can add expressions to built-in policies to further customize them. ::: To learn more, see the [bindings](../../add-secure-apps/bindings-overview/index.md) documentation and the guide on how to [bind a policy to a new application when the application is created](../../add-secure-apps/applications/manage_apps.mdx#create-an-application-and-provider-pair) (for example, to configure application-specific access). ## Create a policy -To create a new policy, _either a pre-configured one or an expression policy_, follow these steps: +To create a policy: 1. Log in to authentik as an administrator and open the authentik Admin interface. 2. Navigate to **Customization** > **Policies**. -3. Click **Create**, and select the type of policy. Here you select whether you want to create a custom expression policy, or a standard, out-of-the-box one. -4. Define the policy and click **Finish**. +3. Click **New Policy**. +4. Select the policy you want to create. +5. Configure the policy-specific settings. +6. Click **Create Policy**. + +If you are not sure which policy type to choose, see [Types of policies in authentik](./types/index.mdx). ## Bind a policy to a flow, stage, application, or source After creating the policy, you can bind it to either a: - [flow](../../add-secure-apps/flows-stages/flow/index.md) -- [stage](../../add-secure-apps/flows-stages/stages/index.md) +- [stage binding](../../add-secure-apps/flows-stages/stages/index.md) - [application](../../add-secure-apps/applications/index.md) - [source](../../users-sources/sources/index.md) @@ -42,23 +50,24 @@ These bindings control which users can access a flow. 2. Navigate to **Flows and Stages** > **Flows**. 3. In the list of flows, click on the name of the flow to which you want to bind a policy. 4. Click on the **Policy/Group/User Bindings** tab at the top of the page. -5. Here, you can decide if you want to create a new policy and bind it to the flow (**Create and bind Policy**), or if you want to select an existing policy and bind it to the flow (**Bind existing policy/group/user**). +5. Either create a new policy and bind it immediately with **Create and bind Policy**, or attach an existing policy, group, or user with **Bind existing policy/group/user**. ### Bind a policy to a stage binding These bindings control which stages are applied to a flow. -::: info -When you bind a policy to a stage binding, this task is done _per flow_, and does not carry across to other flows that might use this same stage. +:::info +When you bind a policy to a stage binding, this task is done per flow, and does not carry across to other flows that might use this same stage. ::: 1. Log in to authentik as an administrator and open the authentik Admin interface. 2. Navigate to **Flows and Stages** > **Flows**. 3. In the list of flows, click on the name of the flow which has the stage to which you want to bind a policy. 4. Click on the **Stage Bindings** tab at the top of the page. -5. Click the arrow (**>**) beside the name of the stage to which you want to bind a policy. - The details for that stage are displayed. -6. Here, you can decide if you want to create a new policy and bind it to the stage binding (**Create and bind Policy**), or if you want to select an existing policy and bind it to the stage binding (**Bind existing policy/group/user**). +5. Click the arrow (**>**) beside the name of the stage to which you want to bind a policy. The details for that stage are displayed. +6. Either create and bind a new policy, or bind an existing policy, group, or user. + +If the policy depends on request data that is only known after the user has interacted with the flow, configure the stage binding to **Evaluate when stage is run** instead of only at planning time. ### Bind a policy to an application @@ -68,9 +77,7 @@ These bindings control which users or groups can access an application. 2. Navigate to **Applications** > **Applications**. 3. In the list of applications, click on the name of the application to which you want to bind a policy. 4. Click on the **Policy/Group/User Bindings** tab at the top of the page. -5. Here, select whether you want to create a new policy and bind it to the application, or select an existing policy and bind it to the application: - - **Create and bind Policy** - - **Bind existing Policy/Group/User** +5. Either create and bind a new policy, or bind an existing policy, group, or user. ### Bind a policy to a source @@ -80,6 +87,6 @@ These bindings control which users or groups can access a source. 2. Navigate to **Directory** > **Federation and Social login**. 3. In the list of sources, click on the name of the source to which you want to bind a policy. 4. Click on the **Policy Bindings** tab at the top of the page. -5. Here, select whether you want to create a new policy and bind it to the source, or select an existing policy and bind it to the source: - - **Create and bind Policy** - - **Bind existing Policy/Group/User** +5. Either create and bind a new policy, or bind an existing policy, group, or user. + +For background on policy ordering, engine mode, and binding options, see [Policy bindings and evaluation](./bindings.md). diff --git a/website/docs/enterprise/enterprise-features.md b/website/docs/enterprise/enterprise-features.md index bd5ac41a52..88d756df28 100644 --- a/website/docs/enterprise/enterprise-features.md +++ b/website/docs/enterprise/enterprise-features.md @@ -51,7 +51,7 @@ This authenticator stage validates Chrome browsers and ChromeOS devices against The SSF Provider enables authentik to transmit real-time security events (e.g., MFA changes, logouts) as Security Event Tokens to subscribed OIDC applications via secure webhooks. Also allows for integration with Apple Business Manager (ABM). -### [Password history compliance checks](../customize/policies/unique_password.md) +### [Password history compliance checks](../customize/policies/types/password-uniqueness.md) The Password Uniqueness Policy blocks reuse of previous passwords by comparing new ones against stored hashes of previous passwords. diff --git a/website/docs/expressions/_functions.mdx b/website/docs/expressions/reference/_functions.mdx similarity index 99% rename from website/docs/expressions/_functions.mdx rename to website/docs/expressions/reference/_functions.mdx index d8ec3b09cf..065c541378 100644 --- a/website/docs/expressions/_functions.mdx +++ b/website/docs/expressions/reference/_functions.mdx @@ -62,7 +62,7 @@ return ak_is_group_member(request.user, name="test_group") Fetch a user matching `**filters`. -Returns `None` if no user was found; otherwise, returns the [User](../users-sources/user/index.mdx) object. +Returns `None` if no user was found; otherwise, returns the [User](../../users-sources/user/index.mdx) object. Example: diff --git a/website/docs/expressions/_objects.md b/website/docs/expressions/reference/_objects.md similarity index 100% rename from website/docs/expressions/_objects.md rename to website/docs/expressions/reference/_objects.md diff --git a/website/docs/expressions/_user.md b/website/docs/expressions/reference/_user.md similarity index 68% rename from website/docs/expressions/_user.md rename to website/docs/expressions/reference/_user.md index 1c39a84bc9..5bedf33ca4 100644 --- a/website/docs/expressions/_user.md +++ b/website/docs/expressions/reference/_user.md @@ -1,4 +1,4 @@ -- `user`: The current user. This may be `None` if there is no contextual user. See [User](../users-sources/user/user_ref.mdx#object-properties). +- `user`: The current user. This may be `None` if there is no contextual user. See [User](../../users-sources/user/user_ref.mdx#object-properties). Example: diff --git a/website/docs/install-config/first-steps/index.mdx b/website/docs/install-config/first-steps/index.mdx index 690cf2406e..159339e29e 100644 --- a/website/docs/install-config/first-steps/index.mdx +++ b/website/docs/install-config/first-steps/index.mdx @@ -70,7 +70,7 @@ For more configuration options and full details about integrating with Grafana, ### 1. Log in to authentik as an administrator and open the authentik Admin interface. - **A.** In the Admin interface, navigate to **Applications** > **Applications** and click **Create with Provider** to create an application and provider pair. + **A.** In the Admin interface, navigate to **Applications** > **Applications** and click **New Application** to create an application and provider pair. :::tip About application and provider pairs Every application that you add to authentik requires a provider, which is used to configure the specific protocol between the application and authentik, for example OAuth2/OIDC, SAML, LDAP, or others. @@ -83,13 +83,13 @@ Every application that you add to authentik requires a provider, which is used t - **Group**: select an optional group for the application; groups are used to visually separate applications. For example, you can choose to group applications that you use for coding from those you use for internal communication. - **Policy engine mode**: select **Any** for this tutorial; the mode determines how strictly policies are adhered to. - TIP: in authentik, - [policies](../../customize/policies/working_with_policies.md) are used in authentik to - fine-tune access to applications, flows, stages and many other authentik components. It is - not required to use a policy at all, though. The _policy engine mode_ setting of **Any** - means that as long as a single policy passes (or if there are no policies bound to the - application), then access to the application is granted. The mode **ALL** means that every - one of any policies bound to the application must pass in order for a user to have access - to the application. + [policies](../../customize/policies/bindings.md) are used in authentik to fine-tune access + to applications, flows, stages and many other authentik components. It is not required to + use a policy at all, though. The _policy engine mode_ setting of **Any** means that as + long as a single policy passes (or if there are no policies bound to the application), + then access to the application is granted. The mode **ALL** means that every one of any + policies bound to the application must pass in order for a user to have access to the + application. - **UI Settings**: optional UI settings that are displayed about the application, including the launch URL, and three settings to display extra information about the application on the **My Applications** page: an optional icon, the publisher of the application, and a brief description. - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. @@ -184,7 +184,7 @@ Now that you can access the authentik Admin interface, and you have added an app - **Is active**: Define the newly created user account as active. - **Attributes**: You can leave this empty for this tutorial. This field can be used to store custom attributes for the user, in YAML or JSON format. These attributes can then be used within property mappings and policies. - **C.** Click **Create**. + **C.** Click **Create User**. ### 2. Verify that the new user was created diff --git a/website/docs/releases/2024/v2024.6.md b/website/docs/releases/2024/v2024.6.md index 3e3b2c93fe..0902433651 100644 --- a/website/docs/releases/2024/v2024.6.md +++ b/website/docs/releases/2024/v2024.6.md @@ -25,7 +25,7 @@ With this release, authentik now enforces unique group names. Existing groups wi ### GeoIP and ASN context object -The `context["geoip"]` and `context["asn"]` objects available in expression policies are now dictionaries. Attributes must now be accessed via dictionary accessors. See [our policy examples](../../customize/policies/expression.mdx) for the updated syntax. +The `context["geoip"]` and `context["asn"]` objects available in expression policies are now dictionaries. Attributes must now be accessed via dictionary accessors. See [our policy examples](../../customize/policies/types/expression/index.mdx) for the updated syntax. ## New features diff --git a/website/docs/releases/2024/v2024.8.md b/website/docs/releases/2024/v2024.8.md index 01c957eacb..fa4802b2a2 100644 --- a/website/docs/releases/2024/v2024.8.md +++ b/website/docs/releases/2024/v2024.8.md @@ -93,7 +93,7 @@ slug: "/releases/2024.8" - **GeoIP Policy** - With the new [GeoIP Policy](../../customize/policies/index.md#geoip-policy) it is possible to grant/deny access based on Country and ASN, without having to write an expression policy. + With the new [GeoIP Policy](../../customize/policies/types/geoip.md) it is possible to grant/deny access based on Country and ASN, without having to write an expression policy. - **Simplification of LDAP Provider permissions** diff --git a/website/docs/releases/2025/v2025.10.md b/website/docs/releases/2025/v2025.10.md index 7eb6fe70b9..0beb91a1cf 100644 --- a/website/docs/releases/2025/v2025.10.md +++ b/website/docs/releases/2025/v2025.10.md @@ -68,7 +68,7 @@ The user library has improved scaling and makes better use of space with a highe - Windows: a custom credential provider allowing custom authentication flows. - macOS: a Platform SSO integration allowing seamless authentication. - Linux: accessing Linux servers via an authentik identity. -- Add `ak_send_email`: Allow for easier sending of emails in expressions; see [ak_send_email](../../customize/policies/expression.mdx). +- Add `ak_send_email`: Allow for easier sending of emails in expressions; see [ak_send_email](../../customize/policies/types/expression/reference.mdx). - Change recovery token duration: When using `ak create_recovery_key`, the duration is now set in minutes instead of years. - Add OIDC `ui_locales` support: The OAuth2 provider now accepts `ui_locales` to set the locale of authentik. - Add support for separate labels and values in prompt choice inputs, see [Prompt stage documentation](../../add-secure-apps/flows-stages/stages/prompt/index.md); thanks to @ErikAhlund! diff --git a/website/docs/releases/2025/v2025.2.md b/website/docs/releases/2025/v2025.2.md index 7a9abe03d3..e11e8ccc4a 100644 --- a/website/docs/releases/2025/v2025.2.md +++ b/website/docs/releases/2025/v2025.2.md @@ -43,7 +43,7 @@ slug: "/releases/2025.2" Add the ability to check for the distance a user has moved compared to a previous login, and add the option to check impossible travel distances based on client IP. - These options can be used to detect and prevent access from potentially stolen authentik sessions or stolen devices. Refer to our [documentation](../../customize/policies/index.md#geoip-policy). + These options can be used to detect and prevent access from potentially stolen authentik sessions or stolen devices. Refer to our [documentation](../../customize/policies/types/geoip.md). - **Email OTP Authenticator Setup Stage** diff --git a/website/docs/releases/2025/v2025.4.md b/website/docs/releases/2025/v2025.4.md index 981e42a303..a3980b91fb 100644 --- a/website/docs/releases/2025/v2025.4.md +++ b/website/docs/releases/2025/v2025.4.md @@ -67,7 +67,7 @@ Previously, sessions were stored by default in the cache. Now, they are stored i -- **Password History Policy**: See [description](#highlights) under Highlights. Refer to our [documentation](../../customize/policies/unique_password.md). +- **Password History Policy**: See [description](#highlights) under Highlights. Refer to our [documentation](../../customize/policies/types/password-uniqueness.md). - **Improve membership resolution for the LDAP Source**: See [description](#highlights) under Highlights. Refer to our [documentation](../../users-sources/sources/directory-sync/active-directory/index.md). diff --git a/website/docs/security/security-hardening.md b/website/docs/security/security-hardening.md index e903601ee7..1edc0de4f8 100644 --- a/website/docs/security/security-hardening.md +++ b/website/docs/security/security-hardening.md @@ -13,11 +13,11 @@ However, for further hardening compliant to the NIST Guidelines, consider - setting the length of the password to a minimum of 15 characters, and - enabling the "Check haveibeenpwned.com" blocklist comparison (note that this cannot be used on Air-gapped instances) -For further options, see [Password policy](../customize/policies/index.md#password-policy). +For further options, see [Password Policy](../customize/policies/types/password.md). ### Expressions -[Expressions](../customize/policies/expression.mdx) allow super-users and other highly privileged users to create custom logic within authentik to modify its behaviour. Editing/creating these expressions is, by default, limited to super-users and any related events are fully logged. +[Expressions](../customize/policies/types/expression/index.mdx) allow super-users and other highly privileged users to create custom logic within authentik to modify its behaviour. Editing/creating these expressions is, by default, limited to super-users and any related events are fully logged. However, for further hardening, it is possible to prevent any user (even super-users) from using expressions to create or edit any objects. To do so, configure your deployment to block API requests to these endpoints: diff --git a/website/docs/sidebar.mjs b/website/docs/sidebar.mjs index 107c7e8ad4..04852f420d 100644 --- a/website/docs/sidebar.mjs +++ b/website/docs/sidebar.mjs @@ -419,21 +419,38 @@ const items = [ }, items: [ "customize/policies/working_with_policies", + "customize/policies/bindings", { type: "category", - label: "Expression Policies", + label: "Policy Types", link: { type: "doc", - id: "customize/policies/expression", + id: "customize/policies/types/index", }, items: [ - "customize/policies/expression/unique_email", - "customize/policies/expression/managing_flow_context_keys", - "customize/policies/expression/source_switch", - "customize/policies/expression/whitelist_email", + "customize/policies/types/event-matcher", + { + type: "category", + label: "Expression Policies", + link: { + type: "doc", + id: "customize/policies/types/expression/index", + }, + items: [ + "customize/policies/types/expression/reference", + "customize/policies/types/expression/unique_email", + "customize/policies/types/expression/managing_flow_context_keys", + "customize/policies/types/expression/source_switch", + "customize/policies/types/expression/whitelist_email", + ], + }, + "customize/policies/types/geoip", + "customize/policies/types/password", + "customize/policies/types/password-expiry", + "customize/policies/types/password-uniqueness", + "customize/policies/types/reputation", ], }, - "customize/policies/unique_password", ], }, { diff --git a/website/docs/static/_redirects b/website/docs/static/_redirects index c0f1d60573..5b94f26b36 100644 --- a/website/docs/static/_redirects +++ b/website/docs/static/_redirects @@ -42,8 +42,19 @@ /customize/interfaces/admin/customization /customize/interfaces/admin/ 301! /customize/interfaces/flow/customization /customize/interfaces/flow/ 301! /customize/interfaces/user/customization /customize/interfaces/user/ 301! -/customize/policies/working_with_policies/unique_email /customize/policies/expression/unique_email/ 301! -/customize/policies/working_with_policies/whitelist_email /customize/policies/expression/whitelist_email/ 301! +/customize/policies/expression /customize/policies/types/expression/ 301! +/customize/policies/expression/managing_flow_context_keys /customize/policies/types/expression/managing_flow_context_keys/ 301! +/customize/policies/expression/source_switch /customize/policies/types/expression/source_switch/ 301! +/customize/policies/expression/unique_email /customize/policies/types/expression/unique_email/ 301! +/customize/policies/expression/whitelist_email /customize/policies/types/expression/whitelist_email/ 301! +/customize/policies/working_with_policies/unique_email /customize/policies/types/expression/unique_email/ 301! +/customize/policies/working_with_policies/whitelist_email /customize/policies/types/expression/whitelist_email/ 301! +/customize/policies/event_matcher /customize/policies/types/event-matcher/ 301! +/customize/policies/geoip /customize/policies/types/geoip/ 301! +/customize/policies/password /customize/policies/types/password/ 301! +/customize/policies/password_expiry /customize/policies/types/password-expiry/ 301! +/customize/policies/reputation /customize/policies/types/reputation/ 301! +/customize/policies/unique_password /customize/policies/types/password-uniqueness/ 301! /interfaces/* /customize/interfaces/:splat 301! /policies/* /customize/policies/:splat 301! #endregion diff --git a/website/docs/sys-mgmt/events/notifications.md b/website/docs/sys-mgmt/events/notifications.md index 8d1e57c623..3aa2035574 100644 --- a/website/docs/sys-mgmt/events/notifications.md +++ b/website/docs/sys-mgmt/events/notifications.md @@ -27,7 +27,7 @@ You will need to create a policy (either the **Event Matcher** policy or a custo ### Event Matcher policy -For simple event matching you can [create and configure](../../customize/policies/working_with_policies.md) an **Event Matcher policy** to define which events (known as _Actions_ in the policy) will trigger a notification. For example, whenever a user deletes a model object, or whenever any user fails to successfully log in. +For simple event matching you can create and configure an [Event Matcher Policy](../../customize/policies/types/event-matcher.md) to define which events (known as _Actions_ in the policy) will trigger a notification. For example, whenever 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. @@ -50,9 +50,9 @@ After you've created the policies to match the events you want, create a notific 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. +2. Click **New Notification Rule** 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 then click **Create** or **Update** to save the settings. +3. Define the policy configurations, and then click **Create Notification Rule** or **Update** to save the settings. - Note that policies are executed regardless of whether a group is selected. However, notifications are only triggered when a group is selected. - You also have to select which [notification transport](./transports.md) should be used to send the notification. Two notification transports are created by default: @@ -61,7 +61,7 @@ After you've created the policies to match the events you want, create a notific 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. +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 Policy Binding** to finalize the binding. :::info Be aware that policies are executed even when no group is selected. diff --git a/website/docs/sys-mgmt/ops/geoip.mdx b/website/docs/sys-mgmt/ops/geoip.mdx index f03aa02677..3180dd4587 100644 --- a/website/docs/sys-mgmt/ops/geoip.mdx +++ b/website/docs/sys-mgmt/ops/geoip.mdx @@ -1,6 +1,6 @@ # GeoIP -authentik supports GeoIP to add additional information to login/authorization/enrollment requests. Additionally, a [GeoIP policy](../../customize/policies/index.md#geoip-policy) can be used to make policy decisions based on the lookup result. +authentik supports GeoIP to add additional information to login/authorization/enrollment requests. Additionally, a [GeoIP Policy](../../customize/policies/types/geoip.md) can be used to make policy decisions based on the lookup result. ### Configuration diff --git a/website/docs/sys-mgmt/settings.md b/website/docs/sys-mgmt/settings.md index feb0679154..488a595a1d 100644 --- a/website/docs/sys-mgmt/settings.md +++ b/website/docs/sys-mgmt/settings.md @@ -42,11 +42,11 @@ Configure how long [Events](./events/index.md) are retained for within authentik ### Reputation: lower limit -Configure a lower limit for [Reputation](../../customize/policies/#reputation-policy). Defaults to `-5`. +Configure a lower limit for [Reputation Policy](../customize/policies/types/reputation.md). Defaults to `-5`. ### Reputation: upper limit -Configure an upper limit for [Reputation](../../customize/policies/#reputation-policy). Defaults to `5`. +Configure an upper limit for [Reputation Policy](../customize/policies/types/reputation.md). Defaults to `5`. ### Footer links diff --git a/website/docs/users-sources/sources/property-mappings/expressions.md b/website/docs/users-sources/sources/property-mappings/expressions.md index ecee21cd4b..6187289490 100644 --- a/website/docs/users-sources/sources/property-mappings/expressions.md +++ b/website/docs/users-sources/sources/property-mappings/expressions.md @@ -10,12 +10,12 @@ The property mapping should return a value that is expected by the source. Retur - `properties`: A Python dictionary containing the result of the previously run property mappings, plus the initial data computed by the source. - `request`: The current request. This may be `None` if there is no contextual request. See ([Django documentation](https://docs.djangoproject.com/en/3.0/ref/request-response/#httprequest-objects)) -import Objects from "../../../expressions/\_objects.md"; +import Objects from "../../../expressions/reference/\_objects.md"; ## Available Functions -import Functions from "../../../expressions/\_functions.mdx"; +import Functions from "../../../expressions/reference/\_functions.mdx"; diff --git a/website/docs/users-sources/user/invitations.md b/website/docs/users-sources/user/invitations.md index 3efcd95e25..13e3bb8db7 100644 --- a/website/docs/users-sources/user/invitations.md +++ b/website/docs/users-sources/user/invitations.md @@ -58,7 +58,7 @@ We have two pre-defined blueprints, the`Example - Invitation-based Enrollment` b ### Step 3. Create the invitation object 1. Log in to authentik as an administrator and open the authentik Admin interface. -2. Navigate to **Directory** > **Invitations** and click **Create**. +2. Navigate to **Directory** > **Invitations** and click **New Invitation**. The Create Invitation box appears. @@ -155,7 +155,7 @@ If you prefer to create your invitation flow manually instead of using a bluepri ### Step 1: Create an Invitation stage 1. Log in to authentik as an administrator and open the authentik Admin interface. -2. Navigate to **Flows and Stages** > **Stages** and click **Create**. +2. Navigate to **Flows and Stages** > **Stages** and click **New Stage**. 3. Select **Invitation Stage** from the stage type list. 4. Configure the stage: - **Name**: Provide a descriptive name (e.g., `enrollment-invitation-stage`) @@ -163,7 +163,7 @@ If you prefer to create your invitation flow manually instead of using a bluepri - Set to `false` if you want to require a valid invitation token (recommended for invitation-only flows). - Set to `true` if you want to allow both invited and non-invited users to use the same enrollment flow. -5. Click **Create**. +5. Click **Create Stage**. :::info The **Continue flow without invitation** setting determines whether users can proceed through the flow without a valid invitation token. When set to `false`, only users with valid invitation links can complete enrollment. @@ -226,7 +226,7 @@ Groups cannot be set directly in invitation custom attributes because they requi ### Expression policies with invitations -You can use [expression policies](../../../customize/policies/expression/) to make decisions based on invitation data: +You can use [expression policies](../../../customize/policies/types/expression/) to make decisions based on invitation data: ```python # Check if user was invited diff --git a/website/docs/users-sources/user/user_basic_operations.md b/website/docs/users-sources/user/user_basic_operations.md index d7897aa27c..313964f1ec 100644 --- a/website/docs/users-sources/user/user_basic_operations.md +++ b/website/docs/users-sources/user/user_basic_operations.md @@ -4,7 +4,7 @@ title: Manage users The following topics are for the basic management of users: how to create, modify, delete or deactivate users, and using a recovery email. -[Policies](../../customize/policies/index.md) can be used to further manage how users are authenticated. For example, by default authentik does not require email addresses be unique, but you can use a policy to [enforce unique email addresses](../../customize/policies/expression/unique_email.md). +[Policies](../../customize/policies/index.md) can be used to further manage how users are authenticated. For example, by default authentik does not require email addresses be unique, but you can use a policy to [enforce unique email addresses](../../customize/policies/types/expression/unique_email.md). ## Create a user @@ -12,7 +12,7 @@ The following topics are for the basic management of users: how to create, modif 1. In the Admin interface of your authentik instance, select **Directory** > **Users** in the left side menu. 2. In the **User folders** area, select the folder where you want to create a user. -3. Click **Create** (for a default user). +3. Click **New User** (for a default user). 4. Fill in the required fields: - **Username**: This value must be unique across your user folders. @@ -25,7 +25,7 @@ The following topics are for the basic management of users: how to create, modif - **Is active**: Define if the newly created user account is active. Selected by default. - **Attributes**: Custom attributes definition for the user, in YAML or JSON format. These attributes can be used to enforce additional prompts on authentication stages or define conditions to enforce specific policies if the current implementation does not fit your use case. The value is an empty dictionary by default. -6. Click **Create** +6. Click **Create User** You should see a confirmation pop-up on the top-right of the screen that the user has been created, and see the new user in the user list. You can directly click the username if you want to [modify your user](./user_basic_operations.md#modify-a-user).