--- name: authentik-proxy-provider-app-link description: "Diagnose and fix an authentik embedded-outpost proxy provider that never authenticates (login wall / raw flow served on the app host): the provider must be linked to an Application, have a non-null invalidation_flow, and an exact external_host match." --- # authentik proxy provider not authenticating (login wall) Symptom: a service behind the authentik embedded outpost (Caddy -> Anubis -> outpost -> app) never lets an authenticated user through. The browser is parked on a login page served ON THE APP'S OWN HOST, e.g. `https://app.example.com/if/flow/default-authentication-flow/?next=/` or `https://app.example.com/flows/-/default/authentication/`. The IdP session cookie lives on `auth.example.com` and is never sent to `app.example.com`, so login is demanded forever. ## Root causes (check in this order) 1. **Provider not linked to an Application (most common).** The embedded outpost's config API filters `ProxyProvider.objects.filter(application__isnull=False)`. A provider created with `ProxyProvider.objects.create(...)` and no Application is never returned to the outpost, so the outpost never loads it and the request falls through to raw flow serving. - FIX: create an Application bound to the provider: ```python app = Application.objects.create(name="Marreta", slug="marreta", launch_url="https://marreta.franksdank.cloud") app.provider = proxy_provider; app.save() proxy_provider.application = app; proxy_provider.save() ``` 2. **Null `invalidation_flow`.** The Rust outpost serde requires a formatted UUID; a null value aborts `get_outpost` with `invalid type: null, expected a formatted UUID string at line 1 column N` and takes down EVERY provider on that outpost. - FIX: `proxy_provider.invalidation_flow = InvalidationFlow.objects.get(name="default-provider-invalidation-flow")`. 3. **`external_host` mismatch.** Must equal the Host header the outpost sees. Trailing-slash mismatch (`https://x` vs `https://x/`) = no match. Match the fleet convention (no trailing slash). 4. **Missing `authentication_flow` / `authorization_flow`.** Set to the fleet defaults (`default-authentication-flow`, `default-provider-authorization-implicit-consent`). ## Diagnose ```bash # 1. Compare broken vs working provider field set (ak shell, as the authentik user): sudo -u authentik AUTHENTIK_POSTGRESQL_HOST=127.0.0.1 AUTHENTIK_POSTGRESQL_PORT=5432 \ AUTHENTIK_POSTGRESQL_NAME=authentik AUTHENTIK_POSTGRESQL_USER=authentik \ AUTHENTIK_POSTGRESQL_PASSWORD='' ak shell ``` ```python for p in ProxyProvider.objects.all(): print(p.name, p.external_host, bool(p.application), p.authentication_flow_id, p.authorization_flow_id, p.invalidation_flow_id) ``` ```bash # 2. The serde error (this is the smoking gun for cause #2): journalctl --user -u authentik-outpost.service --since '-10 min' | grep -iE 'error|invalid|panic' # 3. Confirm the outpost loaded the provider after the fix: journalctl --user -u authentik-outpost.service --since '-2 min' | grep -i 'loaded app' ``` ## Apply + restart After any provider/application change: `systemctl --user restart authentik-server.service authentik-outpost.service` (rootless, user dank on Dankclaw). Then verify the OAuth dance: ```bash curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' https://app.example.com/ # expect 302 -> /outpost.goauthentik.io/start?rd=... (NOT a raw /flows/ URL) ``` ## Provenance note On the Dank fleet these providers are NOT repo-managed (no blueprint). Fixes applied via `ak shell` are live-only. Capture any new provider+application as a repo blueprint or setup script to avoid drift.