nextcloud / nextcloud/user_oidc
TokenInvalidatedListener ends the whole IdP SSO session on local token expiry — no way to disable
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 181
- Forks
- 60
- Avg merge
- 7h 34m
- Merged PRs (30d)
- 26
Description
Which version of user_oidc are you using?
8.6.1 (behavior unchanged on current main)
Describe the issue
lib/Listener/TokenInvalidatedListener.php unconditionally performs an RP-initiated logout at the IdP (server-side GET to the provider's end_session_endpoint with id_token_hint) whenever a Nextcloud auth token is invalidated.
Nextcloud invalidates browser login tokens when they exceed session_lifetime (default 24h since last activity on that token). When that happens, this listener destroys the user's entire IdP SSO session — logging them out of every other application connected to the same IdP realm (in our case Keycloak: portal, chat, webmail, docs...), even though the IdP's own session policy (e.g. 30-day ssoSessionIdleTimeout) says the session should live on.
Observed in production: Keycloak LOGOUT event, client=nextcloud-app, originating from the Nextcloud pod IP, almost exactly session_lifetime after the user's login — followed immediately by every other RP's refresh tokens failing with invalid_grant (Session not active). From the user's perspective, logging into Nextcloud once starts a ~24h timer after which they are logged out of the whole platform.
This is surprising because:
- The IdP is the authority on SSO session lifetime; a single RP's local token expiry silently overrides realm policy for all other RPs.
- Other OIDC clients (Roundcube, oauth2-proxy, portals, etc.) do not end the IdP session when their local token expires — user_oidc is the odd one out.
- There is no admin setting to opt out: the listener only skips when the OIDC session row is missing, the IdP session is already marked closed, or no
end_session_endpointexists (and blanking the endpoint would also break user-initiated logout redirect).
Expected behavior
An admin-configurable switch (app config or per-provider setting, e.g. logout_from_idp_on_token_invalidation) controlling whether token invalidation triggers the IdP end_session call — or defaulting to not ending the IdP session on mere local token expiry (as opposed to explicit user logout, where RP-initiated logout is appropriate and expected).
We currently patch the listener in our deployment to skip only the end_session HTTP call (keeping the session-row cleanup); happy to submit a PR adding a proper config flag if maintainers agree on the desired shape/default.
Steps to reproduce
- Nextcloud behind Keycloak via user_oidc, default
session_lifetime(24h); IdP realm SSO idle/max set to e.g. 30 days. - Log into Nextcloud via OIDC; also log into another app on the same realm (same SSO session).
- Wait for the NC auth token to pass
session_lifetimeand be invalidated (background job or next request). - The IdP session is terminated: the other app's refresh token now fails with
invalid_grant (Session not active); IdP logs a LOGOUT initiated from the Nextcloud server IP.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading lib/Listener/TokenInvalidatedListener.php and trace how token invalidation reaches the IdP end_session call. Check the existing app or provider configuration patterns before choosing the switch shape and default. Done means local session-row cleanup still occurs while the IdP logout call can be disabled for token expiry, without breaking explicit user-initiated logout.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- authentication
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100