goauthentik / goauthentik/authentik
Back-channel logout is only delivered while an access token for the RP is unexpired
- Dominant language
- Python
- Stars
- 25.6k
- Forks
- 2k
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 659
Description
**Version:** authentik 2026.8.1
### What happens
Deleting a user's session in the admin interface notifies the OIDC provider only if that session still has an **unexpired access token for that provider**. With `access_token_validity` configured to five minutes in this deployment, an administrator who ends a session an hour after the user signed in gets **no notification sent at all** — no notification task is queued and, at the normal log level used here, there is no indication that back-channel logout was skipped. The delete itself succeeds and the session disappears from authentik, so from the administrator's side it looks like the user was signed out everywhere.
The relying party, meanwhile, never hears about it and keeps its own session running — in our case a thirty-day session.
### Measurements
Same provider, same configuration, same relying party. The only variable is elapsed time since login.
- **72 minutes after login** — `DELETE /core/authenticated_sessions//` returned 204 and the session was gone. No `backchannel_logout_notification_dispatch` and no `send_backchannel_logout_request` task ran; the worker only logged `outpost_session_end`. The relying party's log stayed silent, and its session row survived.
- **Within 5 minutes of a fresh login** — the same action produced `backchannel_logout_notification_dispatch` and `send_backchannel_logout_request`, both finishing cleanly, the relying party logged the revocation, and the browser was signed out on its next request. End to end in under two seconds.
### Why
The `pre_delete` receiver for `AuthenticatedSession` (`user_session_deleted_oauth_backchannel_logout_and_tokens_removal`) discovers OIDC relying parties exclusively through `AccessToken.objects` filtered by user and session key. Refresh tokens are not consulted. `AccessToken` inherits `ExpiringModel`, whose default manager excludes expired objects, so once the last access token for an RP expires it is no longer returned by this query — even if its database row has not yet been cleaned up. As a result, the ability to send back-channel logout is tied directly to access-token lifetime rather than to the lifetime of the authentik session.
### Why this matters
Back-channel logout exists for the case where a session must be ended out of band: a lost laptop, someone leaving, a credential believed compromised. None of those reliably happen while an access token issued at login is still unexpired. The feature is close to unavailable in precisely the situation it was designed for, and it fails silently on both sides — authentik reports the session deleted, the relying party reports nothing.
authentik's own documentation lists "an administrator deletes a user's session," along with session expiry and revocation, as triggers for back-channel logout. The observed behaviour contradicts that: an administrator ending a session after the access token has expired triggers nothing.
### What we would expect
A session that exists should be notifiable for as long as it exists, independent of whether a short-lived access token happens to be unexpired. `RefreshToken` already carries `provider`, `user` and a session reference (and stores `_id_token`), and is deliberately retained past session deletion (`on_delete=SET_DEFAULT`), so it is available at `pre_delete` to determine the RP binding. Consulting it, or the session's provider bindings directly, would close the gap — and would match the documented behaviour above.
### Note
A relying party can work around this by keeping an access token alive through periodic refresh, and we have done so. That is a workaround for the relying party's own sessions; it does not help any deployment that has not thought about it, which is all of them until they measure.
Contributor guide
Assessment
This issue has not been assessed yet.