OIDC: after a successful single logout, land on the login page that redirects - #20
Merged
Conversation
…edirects Reported from the lab: with single logout and forced redirect both on, signing out left you on management/login.php -- the break-glass page -- rather than on FOG's ordinary login page. That was wrong, and the reasoning behind it was wrong in a specific way. #18 pointed post_logout_redirect_uri at login.php to avoid a loop: index.php on a forced-redirect install sends the browser back to the provider, and if the provider session were still alive that is a silent re-login. But single logout is exactly the case where the provider session is NOT still alive. It was just ended, by the request that is carrying this parameter. So the browser goes back to index.php, index.php sends it to the provider, the provider has no session, and it asks who you are. That is signing out and signing in as somebody else in one continuous journey, which is the thing single logout exists to make possible -- and it was being cut short one page early. So the two landings are now separate, because they answer different questions: OIDC::postLogoutUri() -> management/index.php. The provider session HAS been ended, so bouncing back to it is correct. OIDC::localLoginUrl() -> management/login.php. Used where bouncing back really would loop or silently sign the person in again: - OIDCFlow::_fail(), where the provider just refused, so returning to it is a loop - the USER_LOGGING_OUT fallback when single logout is OFF and forced redirect is on, where the SSO session is untouched and for the URL printed beside the forced-redirect setting, which is the escape hatch and must never be the redirecting page. ADMINS MUST RE-REGISTER: the post-logout redirect URI to register at the provider changes from .../management/login.php to .../management/index.php. The management page prints the current value; providers that follow the spec refuse an unregistered one and show their own error page instead of returning, so an install upgrading from v1.6.9 has to update it there. Both gates updated. The single-logout gate now pins the two URLs separately, pins that they differ (collapsing them re-creates whichever bug the other was avoiding), and pins post_logout_redirect_uri as a KEY and value pair rather than merely mentioning the method -- a mutation that rebound the value to another parameter name survived the first draft. 7/7 mutations caught; sh tests/run-all.sh -> 6 passed, 0 failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017aBSWrDArXHTpKWkkN27LR
This was referenced Aug 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reported from the lab, with single logout and forced redirect both on: signing
out left you on
management/login.php— the break-glass page — instead of FOG'sordinary login page.
Why #18 got this wrong
#18 pointed
post_logout_redirect_uriatlogin.phpto avoid a loop:index.phpon a forced-redirect install sends the browser back to the provider,and if the provider session were still alive that is a silent re-login.
But single logout is exactly the case where the provider session is not still
alive. It was just ended, by the request carrying this parameter. So the
browser returns to
index.php,index.phpsends it to the provider, theprovider has no session, and it asks who you are — signing out and signing in as
somebody else in one continuous journey, which is the thing single logout exists
to make possible. It was being cut short one page early.
The two landings are now separate
They answer different questions, so collapsing them re-creates whichever bug the
other was avoiding:
OIDC::postLogoutUri()management/index.phpOIDC::localLoginUrl()management/login.phplocalLoginUrl()is used in three places, all of them cases where the providermust not be re-entered:
OIDCFlow::_fail()(the provider just refused, soreturning to it is a loop); the
USER_LOGGING_OUTfallback when single logout isoff and forced redirect is on (the SSO session is untouched); and the URL
printed beside the forced-redirect setting, which is the escape hatch and must
never be the redirecting page.
It changes from
…/management/login.phpto…/management/index.php. Providersthat follow the spec refuse an unregistered one and show their own error page
instead of returning, so an install upgrading from v1.6.9 has to update it at the
provider. The management page prints the current value.
Verification
7/7 mutations caught.
sh tests/run-all.sh→ 6 passed, 0 failed.Both gates updated. The single-logout gate now pins the two URLs separately,
pins that they differ, and pins
post_logout_redirect_urias a key/valuepair rather than merely mentioning the method — a mutation that rebound the value
to a different parameter name survived the first draft, which would have meant a
logout that worked and looked broken.
Live-confirmed by the reporter that redirect and logout otherwise work end to end
against Keycloak.
🤖 Generated with Claude Code
https://claude.ai/code/session_017aBSWrDArXHTpKWkkN27LR