From a5abe85148e4820c32042a15bdc977fd960e60cf Mon Sep 17 00:00:00 2001 From: "authentik-automation[bot]" <135050075+authentik-automation[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 14:50:40 +0200 Subject: [PATCH] website/docs: add example recovery flow with MFA (cherry-pick #19497 to version-2026.2) (#21305) website/docs: add example recovery flow with MFA (#19497) * website/docs: add example recovery flow with MFA * Apply suggestion from @tanberry --------- Signed-off-by: Jens Langhammer Signed-off-by: Jens L. Co-authored-by: Jens L. Co-authored-by: Tana M Berry Co-authored-by: Dewi Roberts --- ...flows-recovery-email-mfa-verification.yaml | 178 ++++++++++++++++++ .../flows-stages/flow/examples/flows.md | 8 +- .../user/user_basic_operations.md | 2 +- 3 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 blueprints/example/flows-recovery-email-mfa-verification.yaml diff --git a/blueprints/example/flows-recovery-email-mfa-verification.yaml b/blueprints/example/flows-recovery-email-mfa-verification.yaml new file mode 100644 index 0000000000..776d25a718 --- /dev/null +++ b/blueprints/example/flows-recovery-email-mfa-verification.yaml @@ -0,0 +1,178 @@ +version: 1 +metadata: + labels: + blueprints.goauthentik.io/instantiate: "false" + name: Example - Recovery with email and MFA verification +entries: + - identifiers: + slug: default-recovery-flow + id: flow + model: authentik_flows.flow + attrs: + name: Default recovery flow + title: Reset your password + designation: recovery + authentication: require_unauthenticated + - identifiers: + name: default-recovery-field-password + id: prompt-field-password + model: authentik_stages_prompt.prompt + attrs: + field_key: password + label: Password + type: password + required: true + placeholder: Password + order: 0 + placeholder_expression: false + - identifiers: + name: default-recovery-field-password-repeat + id: prompt-field-password-repeat + model: authentik_stages_prompt.prompt + attrs: + field_key: password_repeat + label: Password (repeat) + type: password + required: true + placeholder: Password (repeat) + order: 1 + placeholder_expression: false + - identifiers: + name: default-recovery-skip-if-restored + id: default-recovery-skip-if-restored + model: authentik_policies_expression.expressionpolicy + attrs: + expression: | + return bool(request.context.get('is_restored', True)) + - identifiers: + name: default-recovery-email + id: default-recovery-email + model: authentik_stages_email.emailstage + attrs: + use_global_settings: true + host: localhost + port: 25 + username: "" + use_tls: false + use_ssl: false + timeout: 10 + from_address: system@authentik.local + token_expiry: minutes=30 + subject: authentik + template: email/password_reset.html + activate_user_on_success: true + recovery_max_attempts: 5 + recovery_cache_timeout: minutes=5 + - identifiers: + name: default-recovery-mfa + id: default-recovery-mfa + model: authentik_stages_authenticator_validate.authenticatorvalidatestage + - identifiers: + name: default-recovery-user-write + id: default-recovery-user-write + model: authentik_stages_user_write.userwritestage + attrs: + user_creation_mode: never_create + - identifiers: + name: default-recovery-identification + id: default-recovery-identification + model: authentik_stages_identification.identificationstage + attrs: + user_fields: + - email + - username + - identifiers: + name: default-recovery-user-login + id: default-recovery-user-login + model: authentik_stages_user_login.userloginstage + - identifiers: + name: Change your password + id: stages-prompt-password + model: authentik_stages_prompt.promptstage + attrs: + fields: + - !KeyOf prompt-field-password + - !KeyOf prompt-field-password-repeat + validation_policies: [] + - identifiers: + target: !KeyOf flow + stage: !KeyOf default-recovery-identification + order: 10 + model: authentik_flows.flowstagebinding + id: flow-binding-identification + attrs: + evaluate_on_plan: true + re_evaluate_policies: true + policy_engine_mode: any + invalid_response_action: retry + - identifiers: + target: !KeyOf flow + stage: !KeyOf default-recovery-email + order: 20 + model: authentik_flows.flowstagebinding + id: flow-binding-email + attrs: + evaluate_on_plan: true + re_evaluate_policies: true + policy_engine_mode: any + invalid_response_action: retry + - identifiers: + target: !KeyOf flow + stage: !KeyOf default-recovery-mfa + order: 21 + model: authentik_flows.flowstagebinding + id: flow-binding-mfa + attrs: + evaluate_on_plan: true + re_evaluate_policies: true + policy_engine_mode: any + invalid_response_action: retry + - identifiers: + target: !KeyOf flow + stage: !KeyOf stages-prompt-password + order: 30 + model: authentik_flows.flowstagebinding + attrs: + evaluate_on_plan: true + re_evaluate_policies: false + policy_engine_mode: any + invalid_response_action: retry + - identifiers: + target: !KeyOf flow + stage: !KeyOf default-recovery-user-write + order: 40 + model: authentik_flows.flowstagebinding + attrs: + evaluate_on_plan: true + re_evaluate_policies: false + policy_engine_mode: any + invalid_response_action: retry + - identifiers: + target: !KeyOf flow + stage: !KeyOf default-recovery-user-login + order: 100 + model: authentik_flows.flowstagebinding + attrs: + evaluate_on_plan: true + re_evaluate_policies: false + policy_engine_mode: any + invalid_response_action: retry + - identifiers: + policy: !KeyOf default-recovery-skip-if-restored + target: !KeyOf flow-binding-identification + order: 0 + model: authentik_policies.policybinding + attrs: + negate: false + enabled: true + timeout: 30 + - identifiers: + policy: !KeyOf default-recovery-skip-if-restored + target: !KeyOf flow-binding-email + order: 0 + state: absent + model: authentik_policies.policybinding + attrs: + negate: false + enabled: true + timeout: 30 diff --git a/website/docs/add-secure-apps/flows-stages/flow/examples/flows.md b/website/docs/add-secure-apps/flows-stages/flow/examples/flows.md index b81bcdd5eb..81b219df64 100644 --- a/website/docs/add-secure-apps/flows-stages/flow/examples/flows.md +++ b/website/docs/add-secure-apps/flows-stages/flow/examples/flows.md @@ -40,11 +40,13 @@ Login flow which conditionally shows the users a captcha, based on the reputatio By default, the captcha test keys are used. You can get a proper key [here](https://www.google.com/recaptcha/intro/v3.html). -## Recovery with email verification +## Recovery with email and MFA verification -Flow: right-click [here](/blueprints/example/flows-recovery-email-verification.yaml) and save the file. +Flow: right-click [here](/blueprints/example/flows-recovery-email-mfa-verification.yaml) and save the file. -Recovery flow, the user is sent an email after they've identified themselves. After they click on the link in the email, they are prompted for a new password and immediately logged on. +With this recovery flow, the user is sent an email after they've identified themselves. After they click on the link in the email, they will have to verify their configured MFA device, and are prompted for a new password and immediately logged on. + +There's also [a version](/blueprints/example/flows-recovery-email-verification.yaml) of this flow available without MFA validation, which is not recommended. ## User deletion diff --git a/website/docs/users-sources/user/user_basic_operations.md b/website/docs/users-sources/user/user_basic_operations.md index 44c414536a..e8ebf14c1b 100644 --- a/website/docs/users-sources/user/user_basic_operations.md +++ b/website/docs/users-sources/user/user_basic_operations.md @@ -118,7 +118,7 @@ Both options require you to configure a recovery flow and set it as the **Defaul ### Configure a recovery flow -To get started, you can [import](../../add-secure-apps/flows-stages/flow/index.md#import-or-export-a-flow) this example flow: [Recovery with email verification flow](../../add-secure-apps/flows-stages/flow/examples/flows.md#recovery-with-email-verification) +To get started, you can [import](../../add-secure-apps/flows-stages/flow/index.md#import-or-export-a-flow) this example flow: [Recovery with email verification flow](../../add-secure-apps/flows-stages/flow/examples/flows.md#recovery-with-email-and-mfa-verification) Then, set this as the default recovery flow for the active brand: