goauthentik / goauthentik/authentik

Embedded proxy outpost (2026.8.1, Rust): JWKS backchannel fails with 'InvalidContentType' on https authentik_host → redirect loop after callback; authentik_host_browser ignored

Open
#25,875 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
25.6k
Forks
2k
Avg merge
1d 1h
Merged PRs (30d)
644

Description

**Describe the bug**

With 2026.8.1 (Rust server + embedded proxy outpost), a Proxy Provider in `forward_single` mode behind Caddy `forward_auth` ends in an infinite redirect loop after the OAuth callback. The embedded outpost fails to fetch the provider's JWKS from `authentik_host` with a TLS error, although the same URL is reachable from inside the container (verified with Python `urllib` → HTTP 200, TLS 1.3).

Outpost log at `/outpost.goauthentik.io/callback`:

```
src/outpost/proxy/application/handlers/mod.rs:285 level=warn
err:
0: error sending request for url (https://auth.example.com/application/o/toolstatus/jwks/)
1: client error (Connect)
2: received corrupt message of type InvalidContentType
Location: src/outpost/proxy/backchannel.rs:115
spantrace: handle_auth_callback (handlers/mod.rs:203) -> handle (handlers/mod.rs:49)
```

A packet capture on the Docker host during the callback shows **no TCP connection at all** from the server container to `auth.example.com:443` (the only outbound 443 connection was to gravatar). So the embedded outpost seems to route the backchannel request to its own in-process server without going over the network, and then fails because the configured `authentik_host` uses the `https` scheme (plaintext listener + TLS client → `InvalidContentType`).

Workaround attempt: setting the embedded outpost config to `authentik_host: http://localhost:9000` and `authentik_host_browser: https://auth.example.com`. Then the backchannel error disappears, but the browser is redirected to `http://localhost:9000/application/o/authorize/...`, i.e. `authentik_host_browser` is not used for the authorize redirect by the Rust outpost. (Verified after restarting the server container.)

Same configuration works as expected on 2026.5.6 (Go outpost), fresh install, same blueprint.

**To Reproduce**

1. Fresh docker-compose install of 2026.8.1 (upstream compose file, server port published on `127.0.0.1:9000`), Caddy in front with a valid Let's Encrypt cert on `https://auth.example.com` → `reverse_proxy 127.0.0.1:9000`.
2. Create a Proxy Provider, mode `forward_single`, external host `https://app.example.com`, assign it to the embedded outpost. Outpost config `authentik_host: https://auth.example.com`.
3. Caddy for `app.example.com` exactly as in the docs: `route { reverse_proxy /outpost.goauthentik.io/* 127.0.0.1:9000; forward_auth 127.0.0.1:9000 { uri /outpost.goauthentik.io/auth/caddy; copy_headers ...; trusted_proxies private_ranges }; ... }`.
4. Open `https://app.example.com/` → login at authentik → callback → redirect loop (`ERR_TOO_MANY_REDIRECTS`), log as above.

**Expected behavior**

Callback succeeds; the outpost fetches the JWKS via network (or handles the in-process shortcut with the correct scheme), and/or `authentik_host_browser` is respected for user-facing redirects.

**Version and Deployment**

- authentik version: 2026.8.1 (also 2026.8.0 not tested); works on 2026.5.6
- Deployment: docker-compose (Docker 29.8.0, Compose v5.5.1), Debian 13, Caddy 2.11.4 as reverse proxy, embedded outpost only

**Additional context**

- `docker compose config` and container env verified; no proxy env vars set in the container.
- Provider had a signing key assigned (JWKS endpoint returns one RS256 key when fetched from outside).
- Possibly related to the 2026.8 Rust rewrite of the proxy outpost; #25643 and #25410 are other post-rewrite proxy regressions.

Contributor guide

Open the contributing guide

Research direction

Start with src/outpost/proxy/backchannel.rs:115 and the callback flow in src/outpost/proxy/application/handlers/mod.rs:203 and :285. Reproduce the embedded outpost callback with the documented Caddy setup, then trace how authentik_host and authentik_host_browser are selected. Done means the callback succeeds without the InvalidContentType redirect loop and browser redirects use the configured browser host.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
authentication, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.