From 2a107cbf146610b5cbdc5dc5a69c918b4dc9345f Mon Sep 17 00:00:00 2001 From: Pieter Date: Tue, 20 Jan 2026 18:13:10 +0100 Subject: [PATCH] fix: Pass API token as command-line arg to recovery script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The recovery flow automation was failing because the Ansible task was piping the API token via stdin (echo -e), but the Python script (create_recovery_flow.py) expects command-line arguments via sys.argv. Changed from: echo -e "$TOKEN\n$DOMAIN" | docker exec -i python3 script.py To: docker exec python3 script.py "$TOKEN" "$DOMAIN" This matches how the Python script is designed (line 365-370). Tested on valk deployment - recovery flow now creates successfully with all features: - Password complexity policy - Email verification - "Forgot password?" link on login page 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- ansible/roles/authentik/tasks/recovery.yml | 85 ++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 ansible/roles/authentik/tasks/recovery.yml diff --git a/ansible/roles/authentik/tasks/recovery.yml b/ansible/roles/authentik/tasks/recovery.yml new file mode 100644 index 0000000..ef6dabd --- /dev/null +++ b/ansible/roles/authentik/tasks/recovery.yml @@ -0,0 +1,85 @@ +--- +# Configure Authentik password recovery flow +# This creates a complete recovery flow with email verification and password complexity validation + +- name: Use bootstrap token for API access + set_fact: + authentik_api_token: "{{ client_secrets.authentik_bootstrap_token }}" + +- name: Copy recovery flow creation script to server + copy: + src: create_recovery_flow.py + dest: /tmp/create_recovery_flow.py + mode: '0755' + +- name: Copy recovery flow script into Authentik container + shell: docker cp /tmp/create_recovery_flow.py authentik-server:/tmp/create_recovery_flow.py + changed_when: false + +- name: Create recovery flow via Authentik API + shell: | + docker exec authentik-server python3 /tmp/create_recovery_flow.py "{{ authentik_api_token }}" "{{ authentik_domain }}" + register: recovery_flow_result + failed_when: false + changed_when: "'Recovery Flow Configuration Complete' in recovery_flow_result.stdout" + +- name: Cleanup recovery flow script from server + file: + path: /tmp/create_recovery_flow.py + state: absent + +- name: Cleanup recovery flow script from container + shell: docker exec authentik-server rm -f /tmp/create_recovery_flow.py + changed_when: false + failed_when: false + +- name: Parse recovery flow result + set_fact: + recovery_flow: "{{ recovery_flow_result.stdout | regex_search('\\{.*\\}', multiline=True) | from_json }}" + when: recovery_flow_result.rc == 0 + failed_when: false + +- name: Display recovery flow configuration result + debug: + msg: | + ======================================== + Authentik Password Recovery Flow + ======================================== + + {% if recovery_flow is defined and recovery_flow.success | default(false) %} + Status: ✓ Configured Successfully + + Recovery Flow UUID: {{ recovery_flow.recovery_flow_uuid }} + Password Policy UUID: {{ recovery_flow.password_complexity_uuid }} + + Features: + - Password complexity: 12+ chars, mixed case, digit, symbol + - Recovery email with 30-minute expiry token + - Username + password on same login page + - "Forgot password?" link on login page + + Test Recovery Flow: + 1. Go to: https://{{ authentik_domain }}/if/flow/default-authentication-flow/ + 2. Click "Forgot password?" link + 3. Enter username or email + 4. Check email for recovery link (sent via Mailgun) + 5. Set new password (must meet complexity requirements) + + ======================================== + {% else %} + Status: ⚠ Configuration incomplete or failed + + This is non-critical - recovery flow can be configured manually. + + To configure manually: + 1. Login to https://{{ authentik_domain }} + 2. Go to Admin > Flows & Stages + 3. Create recovery flow with email verification + + Details: {{ recovery_flow_result.stdout | default('No output') }} + ======================================== + {% endif %} + +- name: Set recovery flow status fact + set_fact: + recovery_flow_configured: "{{ recovery_flow is defined and recovery_flow.success | default(false) }}"