fix(api): logout's post_logout_redirect_uri uses FrontendURL, not BackendURL
Same class of bug as the OIDC callback fix: handleSessionLogout redirected Keycloak's end-session flow back to BackendURL+"/", which 404s in a split-origin deployment (the backend serves no "/" route). Flagged as a known-deferred question in the callback-redirect design spec; fixing it now that it's been hit in practice. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -923,3 +923,13 @@ func TestSessionLogout_ClearsSessionCookieAndRedirectsToEndSession(t *testing.T)
|
||||
t.Fatalf("expected session cookie to be cleared, got %+v", cleared)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionLogout_PostLogoutRedirectUsesFrontendURL(t *testing.T) {
|
||||
verifier := &authmock.Verifier{} // EndSessionResult unset: echoes back postLogoutRedirectURL unchanged
|
||||
s, _ := newTestServerWithAuth(t, verifier)
|
||||
rec := doJSON(t, s.Router(), http.MethodPost, "/api/session/logout", nil)
|
||||
|
||||
if rec.Code != http.StatusFound || rec.Header().Get("Location") != testSessionConfig.FrontendURL+"/" {
|
||||
t.Fatalf("status = %d, Location = %q, want post_logout_redirect_uri = %q", rec.Code, rec.Header().Get("Location"), testSessionConfig.FrontendURL+"/")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,18 @@ type SessionConfig struct {
|
||||
Duration time.Duration
|
||||
Secure bool
|
||||
// BackendURL is this app's own externally reachable origin (e.g.
|
||||
// "https://geniusrun.example.com", no trailing slash), used to build an
|
||||
// absolute post_logout_redirect_uri for the identity provider -- some
|
||||
// providers, including Keycloak, require this to be an absolute URL
|
||||
// matching one registered on the client, not a bare relative path.
|
||||
// "https://geniusrun.example.com", no trailing slash) -- derives
|
||||
// OIDCRedirectURL (config.Config), the only thing that must stay pointed
|
||||
// at the backend itself, since that's where /api/session/callback is
|
||||
// actually served.
|
||||
BackendURL string
|
||||
// FrontendURL is the origin the browser should land on after the OIDC
|
||||
// callback (success or failure) -- see config.Config.FrontendURL for why
|
||||
// this can differ from BackendURL in a split-origin deployment.
|
||||
// FrontendURL is the origin the browser should land on after any
|
||||
// user-facing redirect: the OIDC callback (success or failure) and the
|
||||
// post_logout_redirect_uri sent to the identity provider on logout. Some
|
||||
// providers, including Keycloak, require an absolute URL matching one
|
||||
// registered on the client, not a bare relative path -- see
|
||||
// config.Config.FrontendURL for why this can differ from BackendURL in a
|
||||
// split-origin deployment.
|
||||
FrontendURL string
|
||||
}
|
||||
|
||||
@@ -87,7 +91,7 @@ func (s *Server) handleSessionCallback(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (s *Server) handleSessionLogout(w http.ResponseWriter, r *http.Request) {
|
||||
http.SetCookie(w, auth.ClearCookie(auth.SessionCookieName, s.Session.Secure))
|
||||
http.Redirect(w, r, s.Auth.EndSessionURL(s.Session.BackendURL+"/"), http.StatusFound)
|
||||
http.Redirect(w, r, s.Auth.EndSessionURL(s.Session.FrontendURL+"/"), http.StatusFound)
|
||||
}
|
||||
|
||||
func (s *Server) handleSessionMe(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user