From fadbe104202fed4037949458902cf088833b0115 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 3 Nov 2026 01:16:35 -0800 Subject: [PATCH] fix(authentik): census and repair the OAuth defaults on every proxy provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A proxy provider built by hand in `ak shell` never runs ProxyProvider.set_oauth_defaults() — the REST serializer does, the ORM does not — so the row looks fully configured while redirect_uris is empty (they are derived from external_host by _get_callback_url()), grant_types is [], and authorization_flow is NULL. Each one kills a guarded login in a different, unrelated-looking way, all before any credential is requested: authentik's own "Redirect URI Error" page, then a bodiless HTTP 400 from /application/o/authorize/ once the URIs are filled by hand, and a 500 NoneType.slug in the flow planner. abs-proxy (abs.franksdank.cloud) hit the first two on 2026-11-03. The script calls the vendor's own set_oauth_defaults() and points the authorization flow at default-provider-authorization-implicit-consent for every proxy provider, idempotently; a provider that already matches is untouched, so a deliberate deviation is never flattened. `--check` is the census (exit 1 on drift, writes nothing) for gate use. Applied live 2026-11-03: abs-proxy fixed, the other ten (REST-created) already compliant, census now reports drift: 0. This is authentik DB state and no deployable file carries it — a blueprint re-import or an ak-shell re-creation reverts it and the symptom returns, so the law and the failure signatures are recorded on the outpost page as provisioning rule 3. --- scripts/authentik-proxy-provider-defaults.sh | 95 +++++++++++++++++++ .../Authentik Outpost Reference.md | 12 ++- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100755 scripts/authentik-proxy-provider-defaults.sh diff --git a/scripts/authentik-proxy-provider-defaults.sh b/scripts/authentik-proxy-provider-defaults.sh new file mode 100755 index 0000000..4e1cfe6 --- /dev/null +++ b/scripts/authentik-proxy-provider-defaults.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash +# Census and repair the OAuth2 defaults on every authentik PROXY provider. +# +# A proxy provider built by hand in `ak shell` never runs +# ProxyProvider.set_oauth_defaults() — the REST serializer calls it, the ORM does +# not — so the row looks perfectly configured (external_host, internal_host, +# application bound, embedded-outpost claim present) while three OAuth facts are +# blank. Each one kills the guarded login in a different, unrelated-looking way, +# all BEFORE any credential is asked for: +# +# * redirect_uris empty -> authentik answers its own page: +# "Redirect URI Error — The request fails due to a missing, invalid, or +# mismatching redirection URI (redirect_uri)". Measured on abs-proxy +# (abs.franksdank.cloud) 2026-11-03. +# * grant_types empty -> the authorize endpoint refuses the outpost's +# authorization-code request with a bodiless HTTP 400 (Chromium renders +# "This page isn't working / HTTP ERROR 400"). Same provider, one step +# later, after the URIs were filled in by hand. +# * authorization_flow NULL -> the authorize view crashes building its flow +# planner: AttributeError 'NoneType' object has no attribute 'slug', HTTP +# 500. That is what authentik-grafana-sso-fix.sh exists for. +# +# So: a guard that shows ANY of those three pages is not an Anubis problem and +# not a Caddy problem — run this script before touching the route. +# +# Repair calls the VENDOR's own set_oauth_defaults() (grant_types = authz code + +# client credentials + password, confidential client, the stock scope mappings, +# redirect_uris derived from external_host by _get_callback_url) and points the +# authorization flow at default-provider-authorization-implicit-consent, the flow +# every working provider here uses. Providers that already match are untouched, +# so a deliberate per-provider deviation is never silently flattened. +# +# This is authentik DB state. It is NOT in any deployable file: a blueprint +# re-import, or an ak-shell re-creation of a provider, reverts these facts and +# the symptom returns verbatim. Re-run after any such rebuild. Idempotent. +# +# Usage: authentik-proxy-provider-defaults.sh [--check] +# no argument repair what drifts, print one line per provider +# --check census only, exit 1 if anything drifts (gate use) +# override host: AUTHENTIK_HOST=… +set -euo pipefail +HOST="${AUTHENTIK_HOST:-dankclaw}" +MODE="${1:-}" +case "$MODE" in + "" | --check) : ;; + *) echo "usage: $(basename "$0") [--check]" >&2; exit 2 ;; +esac + +ssh "$HOST" 'podman exec -i authentik-server ak shell' < grants %s, %d redirect URIs, flow %s" + % ([str(g) for g in after.grant_types], len(after.redirect_uris), + after.authorization_flow and after.authorization_flow.slug)) + +print("providers checked, drift: %d" % drift) +raise SystemExit(1 if (CHECK and drift) else 0) +PYEOF + +echo "Verify: walk the guarded vhost in a browser — Anubis solves, authentik" +echo "renders its login form (no Redirect URI Error, no HTTP 400), and the" +echo "callback lands back on the app." diff --git a/serverAppConfigs-docs/Infrastructure/Authentik Outpost Reference.md b/serverAppConfigs-docs/Infrastructure/Authentik Outpost Reference.md index 596ac89..da56f5f 100644 --- a/serverAppConfigs-docs/Infrastructure/Authentik Outpost Reference.md +++ b/serverAppConfigs-docs/Infrastructure/Authentik Outpost Reference.md @@ -56,7 +56,7 @@ correctly — the outpost matches on hostname. ## Provisioning rules for proxy providers -Two provisioning rules, each verified live by an outage: +Three provisioning rules, each verified live by an outage or a dead login: 1. **All three flows are required.** A ProxyProvider created via raw API/ORM with any of `authentication_flow`/`authorization_flow`/`invalidation_flow` @@ -80,6 +80,16 @@ Two provisioning rules, each verified live by an outage: the app. No error is logged anywhere — the SSO "works" and the app never appears. Create the Application with `provider_id` set (the UI does this automatically; raw API/ORM drives must do it explicitly). +3. **A raw ORM create skips the OAuth defaults.** The REST serializer calls + `ProxyProvider.set_oauth_defaults()`; `ProxyProvider.objects.create()` does not. The row + then looks fully configured — external_host, internal_host, application bound, outpost + claimed — while `redirect_uris` is empty (those URIs are *derived* from `external_host` by + `_get_callback_url`) and `grant_types` is `[]`. Both kill the guard before any credential, + in this order: authentik renders its own **"Redirect URI Error"** page, and once the URIs + are filled by hand the next wall is a bodiless **HTTP 400** out of `/application/o/authorize/` + (both measured on `abs-proxy`, 2026-11-03). Census and repair in one idempotent pass, all + providers at once: `scripts/authentik-proxy-provider-defaults.sh`; `--check` prints the + census and exits 1 on drift, and a provider that already matches is left alone. ## OAuth2 relying-party quirks (this fork; corrected live 2026-10-20)