goauthentik / goauthentik/authentik

LDAP outpost bind unusable on 2026.2.6: post-bind "failed to get user info" 403 without a flow session, but a User-Login stage triggers "exceeded stage recursion depth" (regression, cf #18421)

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

Description

### Describe the bug

On **2026.2.6** (server + `ldap` outpost) an LDAP service-account bind cannot complete — there's a catch-22 between two failure modes. This looks like a regression / incomplete fix of #18421 (closed as *completed*, but it has recent "me too" reports on 2025.10+, and it reproduces on 2026.2.6).

**1. Minimal bind flow → the outpost's post-bind "get user info" call is unauthenticated (403).**
With the previously-recommended headless-LDAP recipe — a single `ak-stage-identification` stage with an inline `password_stage` (no separate Password / User-Login stages), plus `search_full_directory` granted object-level on the provider to the bind account's role — the outpost authenticates but then fails:

```
{"bindDN":"cn=ldap-bind,ou=users,dc=example,dc=com","event":"User has access","level":"info",...}
{"bindDN":"cn=ldap-bind,ou=users,dc=example,dc=com","error":"403 Forbidden (Authentication credentials were not provided.)","event":"failed to get user info","level":"warning",...}
```
`ldapsearch` returns `Operations error (1)`. The flow authenticates (`User has access`), but the subsequent `get user info` API call is sent **without credentials** — the minimal flow established no session.

**2. Adding a User Login stage (to create that session) → `exceeded stage recursion depth`.**
```
{"bindDN":"cn=ldap-bind,ou=users,dc=example,dc=com","error":"exceeded stage recursion depth","event":"failed to execute flow",...,"took-ms":33000}
```
`ldapsearch` returns `Invalid credentials (49)`. Tried: identification(inline password)+login, and identification + separate Password + Login; both `cached` and `direct` bind/search modes. **Every variant with a User-Login stage recurses** (this is the #18421 behavior).

So on 2026.2.6: **no User-Login stage → `get user info` 403; User-Login stage → recursion.** Neither binds.

On **2025.2.4** the minimal-flow (no user-login) + `search_full_directory` recipe worked — the outpost did **not** require a session for `get user info`. That 403-needs-a-session behavior appears to be **new in 2026.2.x**, and it interacts with the still-present recursion to make LDAP binds impossible.

### To reproduce

1. authentik **2026.2.6** server + `ldap` outpost (Kubernetes).
2. LDAP provider bound by an `Application`; provider `authorization_flow` = an `authentication`-designation flow.
3. Flow = a single `ak-stage-identification` (`user_fields: [username]`, inline `password_stage`). Grant `search_full_directory` object-level on the provider to the bind account's role.
4. `ldapsearch -x -H ldap://:3389 -D 'cn=ldap-bind,ou=users,' -w '' -b '' '(cn=ldap-bind)'` → `Operations error (1)`; outpost log: `User has access` then `failed to get user info` **403**.
5. Add an `ak-stage-user-login` binding (order 20), restart the outpost, retry → `Invalid credentials (49)`; outpost log: `exceeded stage recursion depth`.

### Version and Deployment

- authentik **2026.2.6** — `ghcr.io/goauthentik/server:2026.2.6` + `ghcr.io/goauthentik/ldap:2026.2.6`, Kubernetes.

### Additional context

#18421 (closed as completed) has recent reports of the identical `failed to get user info` error, which suggests the earlier fix didn't cover the outpost's **post-bind user-info** path. The `get user info` request being sent with no `Authorization` header when the flow yields no session looks like the core issue on 2026.2.x.

Contributor guide

Open the contributing guide

Research direction

Start by tracing the LDAP outpost post-bind “get user info” request after the authentication flow, then compare the no-User-Login and User-Login paths described in the reproduction. Use the 403 without a flow session and the recursion-depth failure as the failing behaviors; done means the LDAP bind completes without either error on the stated versions and flow variants.

Written by the indexing model from the issue text.

Assessment

Tech stack
kubernetes, python
Domain
authentication, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.