goauthentik / goauthentik/authentik

Back-Channel Logout fires for sessions that have not expired, sometimes ending unrelated users' sessions in the same batch

Open
#25,809 2 comments 0 reactions 1 assignee Claimed by @PeshekDotDev View on GitHub
bug triage
Dominant language
Python
Stars
25.6k
Forks
2k
Avg merge
1d 1h
Merged PRs (30d)
644

Description

### Describe the bug

Description:
We're seeing OIDC Back-Channel Logout notifications get sent for OAuth2 sessions that are nowhere near their configured expiry — sometimes as little as ~30 seconds after the session was created, sometimes several minutes. This happens with no user-initiated logout, no admin action, and no corresponding entry anywhere in Authentik's own Events API. We initially suspected our own OAuth2 Provider's Access Token Validity, but the strongest evidence points somewhere else: on two separate occasions, two completely unrelated user accounts (different users, different browsers, different sessions, different sids) had Back-Channel Logout notifications fired for both of them within under a second of each other, with their logout_tokens carrying identical iat/exp values down to the second. That's only possible if a single internal batch process ended both sessions together — not two independent, coincidentally-timed expirations.

Environment
authentik version: 2026.5.3 (self-hosted, Kubernetes)
Custom OIDC client (our own SSO portal) using Authentik's flow-executor directly for interactive login, then a server-driven recovery-link round trip through a dedicated flow (single User Login Stage, session_duration=hours=1) to establish a real OIDC session for our own client — this "session-sync" round trip happens frequently, once per app-switch in our own gateway UX, so we create many of these session objects per user per day.
Two outposts configured (one embedded, one proxy provider for a separate app), both currently refresh_interval: minutes=5 at the time of the reports below.
What we ruled out first
OAuth2/OpenID Provider Access Token Validity — confirmed via live testing that even with this set to hours=1, sessions still ended within a few minutes on some occasions. Captured logout_token claims confirm the token itself was genuinely valid for another ~57 minutes at the moment it was revoked.
Proxy Provider Token validity (hours=24) — same, not the cause.
OAuth2 grant supersession (a legitimate, expected Back-Channel Logout case when a newer grant for the same user+client supersedes an older one) — we already handle this correctly by tracking the current sid per user and ignoring notifications for a superseded one; the occurrences below are for the sid our own app believes is current.
Evidence: two unrelated sessions ended in the same batch, twice
Occurrence 1 (redacted usernames: user-A, user-B):

backchannelLogout: full claims {"iss":"https://auth.example.com/application/o/our-client/","aud":"","iat":1788629038,"exp":1788632638,"jti":"9a94f289-...","events":{"http://schemas.openid.net/event/backchannel-logout":{}},"sub":"user-A","sid":"62c68f88...bbe7"}
backchannelLogout: full claims {"iss":"https://auth.example.com/application/o/our-client/","aud":"","iat":1788629038,"exp":1788632638,"jti":"7ab15969-...","events":{"http://schemas.openid.net/event/backchannel-logout":{}},"sub":"user-B","sid":"a00051a6...abf0"}
Both iat=1788629038 and exp=1788632638 — identical to the second, for two different users with two different sids.

Occurrence 2, ~13 minutes later, three notifications within one second (user-A on two different providers, user-B on one):

"sub":"user-A","sid":"4c5c94ad...bd7e7","iat":1788629811,"exp":1788633411 (provider: app-2, shared receiver)
"sub":"user-A","sid":"4c5c94ad...bd7e7","iat":1788629812,"exp":1788633412 (provider: our-client)
"sub":"user-B","sid":"c6a26796...8929b","iat":1788629812,"exp":1788633412 (provider: our-client)
Again, near-identical iat/exp across genuinely unrelated sessions.

Correlated worker log (authentik-worker), occurrence 1's window
Immediately before both dispatches, we see paired outpost_session_end tasks (one per configured outpost) for what appear to be two separate underlying sessions, each followed by backchannel_logout_notification_dispatch / send_backchannel_logout_request:

outpost_session_end → "Sending session end signal to outpost" (outpost 1)
outpost_session_end → "Sending session end signal to outpost" (outpost 1) [second session]
backchannel_logout_notification_dispatch → send_backchannel_logout_request enqueued
outpost_session_end → "Sending session end signal to outpost" (outpost 2)
outpost_session_end → "Sending session end signal to outpost" (outpost 2) [second session]
backchannel_logout_notification_dispatch → send_backchannel_logout_request enqueued
We could not find a authentik.core.tasks.clean_expired_models (or similar scheduled task) log line immediately adjacent in every case, but that task is visibly running on the standard ~5-minute cadence throughout our logs (via django_dramatiq_postgres.scheduler's "Sent N scheduled tasks" lines), and the batching signature (multiple unrelated sessions processed together, sharing one dispatch-time iat) strongly resembles the class of bug fixed in [#9598](https://github.com/goauthentik/authentik/issues/9598) ("core: fix task clean_expiring_models removing valid sessions with using database storage", released in 2024.4.2) — except we're on a much newer version, so if related this looks like either a regression or a similar-but-distinct issue in the same area.

Also checked
Authentik's own Events API (/api/v3/events/events/), queried directly and unfiltered for the affected users around these exact timestamps — zero events correlate with either the session ending or the logout. The only visible activity is the next real login (a full interactive re-authentication, including MFA) several minutes later.

Sources:

[core: fix task clean_expiring_models removing valid sessions with using database storage · Issue #9598 · goauthentik/authentik](https://github.com/goauthentik/authentik/issues/9598)
[authentik version 2026.8 is here!](https://goauthentik.io/blog/2026-09-01-authentik-version-2026-8/)
[Release Release 2026.5.6 · goauthentik/authentik](https://github.com/goauthentik/authentik/releases/tag/version%2F2026.5.6)

### How to reproduce

We don't yet have a minimal, isolated reproduction outside our own application — it's only surfaced under fairly heavy use of the recovery-link/session-sync pattern described above, run against real production traffic over several hours. Happy to provide further log excerpts, our exact flow/stage configuration, or test against a specific patched build if that would help narrow it down.

### Expected behavior

A session should only be ended (and Back-Channel Logout dispatched) when it actually reaches its own configured expiry, is explicitly logged out, or is genuinely superseded by a newer grant for the same user — never as a side effect of an unrelated user's session being processed in the same internal batch.

### Screenshots

_No response_

### Additional context

_No response_

### Deployment Method

Kubernetes

### Version

2026.5.3

### Relevant log output

```shell
Occurrence 1 (redacted usernames: user-A, user-B):

backchannelLogout: full claims {"iss":"https://auth.example.com/application/o/our-client/","aud":"","iat":1788629038,"exp":1788632638,"jti":"9a94f289-...","events":{"http://schemas.openid.net/event/backchannel-logout":{}},"sub":"user-A","sid":"62c68f88...bbe7"}
backchannelLogout: full claims {"iss":"https://auth.example.com/application/o/our-client/","aud":"","iat":1788629038,"exp":1788632638,"jti":"7ab15969-...","events":{"http://schemas.openid.net/event/backchannel-logout":{}},"sub":"user-B","sid":"a00051a6...abf0"}
Both iat=1788629038 and exp=1788632638 — identical to the second, for two different users with two different sids.

Occurrence 2, ~13 minutes later, three notifications within one second (user-A on two different providers, user-B on one):

"sub":"user-A","sid":"4c5c94ad...bd7e7","iat":1788629811,"exp":1788633411 (provider: app-2, shared receiver)
"sub":"user-A","sid":"4c5c94ad...bd7e7","iat":1788629812,"exp":1788633412 (provider: our-client)
"sub":"user-B","sid":"c6a26796...8929b","iat":1788629812,"exp":1788633412 (provider: our-client)
Again, near-identical iat/exp across genuinely unrelated sessions.

Correlated worker log (authentik-worker), occurrence 1's window
Immediately before both dispatches, we see paired outpost_session_end tasks (one per configured outpost) for what appear to be two separate underlying sessions, each followed by backchannel_logout_notification_dispatch / send_backchannel_logout_request:

outpost_session_end → "Sending session end signal to outpost" (outpost 1)
outpost_session_end → "Sending session end signal to outpost" (outpost 1) [second session]
backchannel_logout_notification_dispatch → send_backchannel_logout_request enqueued
outpost_session_end → "Sending session end signal to outpost" (outpost 2)
outpost_session_end → "Sending session end signal to outpost" (outpost 2) [second session]
backchannel_logout_notification_dispatch → send_backchannel_logout_request enqueued
```

### **Update: reproduced via an explicit admin-API session delete, not just the periodic sweep**
New finding since filing this: the same cascade can be triggered on demand, by an explicit DELETE /api/v3/core/authenticated_sessions// call for a single user's own session — not only by whatever periodic sweep was batching the earlier occurrences.

What we did
Our own backend calls this endpoint as part of a normal "log this one user out everywhere" action:

GET /api/v3/core/authenticated_sessions/?user= (list that ONE user's own sessions)
DELETE /api/v3/core/authenticated_sessions// (delete each one)
We re-audited our own code calling this and confirmed it is precisely scoped — the pk passed in is always the single account being logged out, resolved directly from that account's own username/email, with no shared state or cross-referencing with any other account anywhere in the call path.

What happened
Three separate, unrelated user accounts were logged into three separate browsers. We triggered a normal logout for one of them (user-1, via the flow above). Within 4–5 seconds, the other two unrelated accounts' sessions also ended, each via a genuine, correctly-signed Back-Channel Logout notification with a sid matching what our app had on record as their current session — i.e., Authentik itself decided to end sessions we never asked it to touch.

10:37:25 user-1 logged out (our own explicit DELETE call — no Back-Channel Logout involved, this is the direct action)
10:37:29 user-2's session ends via Back-Channel Logout ("detected via back-channel" in our own audit log)
10:37:30 user-3's session ends via Back-Channel Logout (same)
user-2 and user-3 had no relationship to user-1's account, were on completely different browsers, and neither our app nor (as far as we can tell) any human action touched their sessions directly.

Why this is a stronger repro than what we had
The original report's evidence (identical iat/exp across unrelated sessions) came from occurrences we could only observe after the fact, on Authentik's own ~5-minute internal cadence — we couldn't trigger it on demand. This time, a single explicit DELETE on one session's own admin-API endpoint appears to have triggered whatever internal reconciliation/cleanup logic is misidentifying other sessions as also needing to end. If this holds up under repeated testing, it suggests the trigger may not be purely time-based (the periodic cleanup task) but something in the session-deletion code path itself doing a broader-than-intended sweep.

We're happy to try to narrow this down further — e.g., testing whether the effect is deterministic (does it happen every time one session is deleted, or only sometimes), and whether it depends on how many other sessions happen to exist at that moment — if that would help.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.