Skip to content

fix(login): treat already-logged-out as success in backchannel logout (#1430)#1431

Open
SAY-5 wants to merge 2 commits intonextcloud:mainfrom
SAY-5:fix/backchannel-logout-already-logged-out-1430
Open

fix(login): treat already-logged-out as success in backchannel logout (#1430)#1431
SAY-5 wants to merge 2 commits intonextcloud:mainfrom
SAY-5:fix/backchannel-logout-already-logged-out-1430

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented Apr 28, 2026

Closes #1430.

Summary

Per OIDC Backchannel Logout 1.0 §2.6:

If the identified End-User is already logged out at the RP when the logout request is received, the logout is considered to have succeeded.

Today backChannelLogout() returns HTTP/400 when the (sid, iss) or (sub, iss) lookup yields no matching session, which is exactly the already-logged-out case the spec calls out as a success. The reporter (running LemonLDAP) sees a confusing error surfaced on the IdP UI even though the desired state — the RP session being gone — is already true. The same shape would happen with Keycloak, Authelia, etc.

Change

Only the two "session not found" paths flip to HTTP/200:

  • findSessionBySidDoesNotExistException ⇒ return HTTP/200 OK + debug log.
  • findSessionsBySubAndIss returns empty ⇒ return HTTP/200 OK + debug log.

The other validation branches in the same method — invalid issuer, invalid signature, malformed token, missing claims, multiple-sessions-found — keep their HTTP/400 responses. Operators that need visibility into already-logged-out backchannel calls can flip Nextcloud's loglevel to debug and see the [BackchannelLogout] line.

Mirrors the proposed fix in the issue and the spec citation.

Test plan

  • No LoginControllerTest exists in tests/unit/Controller/ today, and the existing integration runner under tests/integration/ does not cover the backchannel flow. The change is two short branches that swap a getBackchannelLogoutErrorResponse() for new JSONResponse([], Http::STATUS_OK) plus a debug log; both branches are syntactically equivalent to the existing return new JSONResponse([], Http::STATUS_OK) at the end of the success path.
  • Ran git diff --check clean.
  • Verified the spec citation against the linked RFC section.

Notes

  • This is the spec-compliant behavior; existing IdPs will start receiving cleaner success responses for the already-logged-out case.
  • The optional "debug checkbox" the reporter floated is left for follow-up — the spec is unambiguous, so a per-provider opt-out adds configuration surface for no clear benefit.

Closes nextcloud#1430.

OIDC Backchannel Logout 1.0 §2.6 says:

  'If the identified End-User is already logged out at the RP when
   the logout request is received, the logout is considered to have
   succeeded.'

Today `backChannelLogout()` returns HTTP/400 when the (sid, iss)
or (sub, iss) lookup yields no matching session, even though that
is exactly the already-logged-out case the spec calls out as a
*success*. IdPs (e.g. LemonLDAP, Keycloak) surface this 400 to the
end user and log a spurious error.

The other validation branches in this method — invalid issuer,
invalid signature, missing claims, malformed token — keep their
HTTP/400 responses. Only the two 'session not found' paths flip
to HTTP/200 + a debug log so administrators can still trace what
happened.

See https://openid.net/specs/openid-connect-backchannel-1_0.html#BCActions

Signed-off-by: SAY-5 <say.apm35@gmail.com>
@Spitfireap
Copy link
Copy Markdown

Thanks !
tested on v33.0.2 without any issue. It's working as intended

Copy link
Copy Markdown
Member

@julien-nc julien-nc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot. Small adjustments and let's get this in!

Comment thread lib/Controller/LoginController.php Outdated
// out is a success). Same rationale as the (sid,iss)
// branch above.
$this->logger->debug(
'[BackchannelLogout] no RP sessions for (sub,iss) — treating as already-logged-out per spec',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'[BackchannelLogout] no RP sessions for (sub,iss) — treating as already-logged-out per spec',
'[BackchannelLogout] no RP sessions for (sub,iss) — treating as already-logged-out',

Comment thread lib/Controller/LoginController.php Outdated
// state — the RP session being gone — is already true.
// See https://openid.net/specs/openid-connect-backchannel-1_0.html#BCActions
$this->logger->debug(
'[BackchannelLogout] no RP session for (sid,iss) — treating as already-logged-out per spec',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'[BackchannelLogout] no RP session for (sid,iss) — treating as already-logged-out per spec',
'[BackchannelLogout] no RP session for (sid,iss) — treating as already-logged-out',

Comment thread lib/Controller/LoginController.php Outdated
Comment on lines +933 to +940
// Per OIDC Backchannel Logout 1.0 §2.6:
// "If the identified End-User is already logged out at the
// RP when the logout request is received, the logout is
// considered to have succeeded." Returning 400 here
// causes IdPs (e.g. LemonLDAP, Keycloak) to surface a
// confusing error to the user even though the desired
// state — the RP session being gone — is already true.
// See https://openid.net/specs/openid-connect-backchannel-1_0.html#BCActions
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make this a little bit shorter? The link + a very brief explanation should be enough.

SAY-5 added a commit to SAY-5/user_oidc that referenced this pull request Apr 29, 2026
Address julien-nc's review:

  - Shorten the long rationale comment to a one-liner with the spec
    link, per inline review at lib/Controller/LoginController.php:940.
  - Drop the redundant ' per spec' suffix from both already-logged-out
    debug log lines (lib/Controller/LoginController.php:942 and :972),
    matching the suggested edits.

Behaviour is unchanged — only comment / log message wording.
@SAY-5
Copy link
Copy Markdown
Author

SAY-5 commented Apr 29, 2026

Thanks for the review @julien-nc — applied all three suggestions in aa87b8f: comment block shortened to a single line + spec link, and the redundant ' per spec' suffix dropped from both debug log messages.

@julien-nc
Copy link
Copy Markdown
Member

Thanks for the adjustments. Could you sign your commits like indicated in the DCO check output?

Address julien-nc's review:

  - Shorten the long rationale comment to a one-liner with the spec
    link, per inline review at lib/Controller/LoginController.php:940.
  - Drop the redundant ' per spec' suffix from both already-logged-out
    debug log lines (lib/Controller/LoginController.php:942 and :972),
    matching the suggested edits.

Behaviour is unchanged — only comment / log message wording.

Signed-off-by: SAY-5 <say.apm35@gmail.com>
@SAY-5 SAY-5 force-pushed the fix/backchannel-logout-already-logged-out-1430 branch from aa87b8f to abe6772 Compare April 29, 2026 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RP initiated logout makes backchannel logout throw an HTTP/400 error

3 participants