Skip to content

OIDC: after a successful single logout, land on the login page that redirects - #20

Merged
mastacontrola merged 1 commit into
mainfrom
oidc-logout-landing
Aug 18, 2026
Merged

OIDC: after a successful single logout, land on the login page that redirects#20
mastacontrola merged 1 commit into
mainfrom
oidc-logout-landing

Conversation

@mastacontrola

Copy link
Copy Markdown
Member

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's
ordinary login page.

Why #18 got this wrong

#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 carrying this parameter. So the
browser returns to index.php, index.php sends it to the provider, the
provider 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:

Method Lands on Because
OIDC::postLogoutUri() management/index.php The provider session has been ended, so bouncing back to it is correct
OIDC::localLoginUrl() management/login.php Bouncing back would loop or silently re-authenticate

localLoginUrl() is used in three places, all of them cases where the provider
must not be re-entered: OIDCFlow::_fail() (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 (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.

⚠️ Admins must re-register the post-logout redirect URI

It changes from …/management/login.php to …/management/index.php. 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 at the
provider. The management page prints the current value.

Verification

7/7 mutations caught. sh tests/run-all.sh6 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_uri as a key/value
pair 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

…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
@mastacontrola
mastacontrola merged commit f82114e into main Aug 18, 2026
2 checks passed
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.

1 participant