version: 1 metadata: labels: blueprints.goauthentik.io/instantiate: "true" name: Recovery with email verification context: token_expiry: {{ if eq (env "EMAIL_TOKEN_EXPIRY_MINUTES") "" }} 30 {{ else }} {{ env "EMAIL_TOKEN_EXPIRY_MINUTES" }} {{ end }} subject: {{ if eq (env "EMAIL_SUBJECT") "" }} Account Recovery {{ else }} {{ env "EMAIL_SUBJECT" }} {{ end }} entries: ### DEPENDENCIES - model: authentik_blueprints.metaapplyblueprint attrs: identifiers: name: Default - Authentication flow required: true ### FLOW - identifiers: slug: default-recovery-flow model: authentik_flows.flow state: created attrs: name: Default recovery flow title: Reset your password designation: recovery authentication: require_unauthenticated ### STAGES - identifiers: name: default-recovery-email id: default-recovery-email model: authentik_stages_email.emailstage attrs: use_global_settings: true token_expiry: !Context token_expiry subject: !Context subject template: email/password_reset.html activate_user_on_success: true - identifiers: name: default-recovery-identification id: default-recovery-identification model: authentik_stages_identification.identificationstage attrs: user_fields: - email - username ### STAGE BINDINGS - identifiers: target: !Find [authentik_flows.flow, [slug, default-recovery-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: !Find [authentik_flows.flow, [slug, default-recovery-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: !Find [authentik_flows.flow, [slug, default-recovery-flow]] stage: !Find [authentik_stages_prompt.promptstage, [name, default-password-change-prompt]] 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: !Find [authentik_flows.flow, [slug, default-recovery-flow]] stage: !Find [authentik_stages_user_write.userwritestage, [name, default-password-change-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: !Find [authentik_flows.flow, [slug, default-recovery-flow]] stage: !Find [authentik_stages_user_login.userloginstage, [name, default-authentication-login]] order: 100 model: authentik_flows.flowstagebinding attrs: evaluate_on_plan: true re_evaluate_policies: false policy_engine_mode: any invalid_response_action: retry ### POLICIES - identifiers: name: default-recovery-skip-if-restored id: default-recovery-skip-if-restored model: authentik_policies_expression.expressionpolicy attrs: expression: | return request.context.get('is_restored', False) - identifiers: policy: !KeyOf default-recovery-skip-if-restored target: !KeyOf flow-binding-identification order: 0 model: authentik_policies.policybinding attrs: negate: false enabled: false # TODO: why does this doesn't work? 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