--- name: authentik-claim-cache-purge description: "Fix persistent 403s at Caddy RBAC header gates after authentik group changes: purge the embedded outpost's proxysession claim cache and verify silent re-auth" --- # Authentik outpost claim-cache purge Use when a user gets persistent 403s at a Caddy `header_regexp` RBAC gate (e.g. `/admin`) even though their authentik group membership is correct, and re-login did not help. ## Mechanism (authentik 2026.8, this fleet) - The embedded outpost does NOT re-evaluate groups per request. Each completed authorize writes one row to `authentik_providers_proxy_proxysession`; `session_data` JSON holds the claims (incl. `groups`) served for that browser session until the row expires (observed TTLs 1–24 h per row). - A session minted before the group add keeps serving the old group list → gate 403s forever until expiry. - The 403 happens at Caddy and generates ZERO authentik events — silence in `authentik_events_event` is expected. - Re-login does not fix it: the browser's outpost cookie re-maps to the same stale row. - `proxysession.user_id` is null; map rows to users via `session_data->'claims'->>'preferred_username'`. ## Diagnosis (run on dankclaw) ```bash podman exec authentik-postgres psql -U authentik -d authentik -At -c "SELECT session_data->'claims'->>'preferred_username' AS user, session_data->'claims'->>'groups' AS cached_groups, expires FROM authentik_providers_proxy_proxysession ORDER BY expires;" ``` Stale row = `cached_groups` missing the new group while repo/Caddy gate expects it. ## Fix ```bash podman exec authentik-postgres psql -U authentik -d authentik -At -c "WITH d AS (DELETE FROM authentik_providers_proxy_proxysession WHERE session_data->'claims'->>'preferred_username' IN ('') RETURNING 1) SELECT 'deleted='||count(*) FROM d;" ``` - The user's authentik django login session is untouched → next visit re-authorizes SILENTLY (no password prompt) with fresh claims. - NEVER rotate `AUTHENTIK_SECRET_KEY` for this — it invalidates every outpost session fleet-wide. ## Verification without the user's password Simulate their browser: delete a TEST user's proxysession rows (e.g. `qa-e2e-admin`), keep its e2e storage state on disk, then run the admin spec bypassing setup (setup ALWAYS fresh-logins, which would mask the path): ```bash cd tests/e2e && npx playwright test --project=admin --no-deps ``` Passing with no login prompt = silent re-auth proven. `--no-deps` is required because project dependencies would rerun setup. ## Doc Mechanism + SQL live in `serverAppConfigs-docs/Infrastructure/Authentik.md`, section "Outpost claim cache (proxysession)" (commit ea0bba3).