From 6e8b05c67908ac6322b4b5f6a2c1a9f83483a34d Mon Sep 17 00:00:00 2001 From: DCCONSTRUCTIONS Date: Tue, 5 May 2026 09:01:07 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=A1=D0=9F=D0=A0=D0=90=D0=92=D0=9B?= =?UTF-8?q?=D0=95=D0=9D=D0=98=D0=95=20-=20NODEDC=20LAUNCHER:=20restore=20r?= =?UTF-8?q?eliable=20IdP=20logout=20handoff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/dev-server.mjs | 56 ++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/server/dev-server.mjs b/server/dev-server.mjs index b787b75..d3b3916 100644 --- a/server/dev-server.mjs +++ b/server/dev-server.mjs @@ -167,6 +167,20 @@ app.get("/auth/session-sync", (req, res) => { res.type("html").send(renderSessionSyncBridgePage(allowedOrigins)); }); +app.get("/logout", (req, res) => { + const session = getCurrentSession(req); + + if (session) { + sessions.delete(session.id); + } + + res.clearCookie(sessionCookieName, clearCookieOptions()); + setNoStore(res); + res.type("html").send( + "NODE.DC Launcher session closed." + ); +}); + app.get("/auth/logout", asyncRoute(async (req, res) => { const session = getCurrentSession(req); const returnTo = sanitizeReturnTo(req.query.returnTo); @@ -188,21 +202,19 @@ app.get("/auth/logout", asyncRoute(async (req, res) => { const endSessionEndpoint = discovery.end_session_endpoint; const loginRedirectUrl = buildLoginRedirectUrl(returnTo, { forceLogin: true }); - if (!endSessionEndpoint) { + if (!endSessionEndpoint || !session?.tokenSet.idToken) { setNoStore(res); - res.type("html").send(renderGlobalLogoutPage(getFrontchannelLogoutUrls(), null, loginRedirectUrl)); + res.type("html").send(renderGlobalLogoutPage(getFrontchannelLogoutUrls(), loginRedirectUrl)); return; } const logoutUrl = new URL(endSessionEndpoint); logoutUrl.searchParams.set("client_id", config.clientId); - - if (session?.tokenSet.idToken) { - logoutUrl.searchParams.set("id_token_hint", session.tokenSet.idToken); - } + logoutUrl.searchParams.set("post_logout_redirect_uri", buildLoggedOutRedirectUrl(returnTo)); + logoutUrl.searchParams.set("id_token_hint", session.tokenSet.idToken); setNoStore(res); - res.type("html").send(renderGlobalLogoutPage(getFrontchannelLogoutUrls(), logoutUrl.toString(), loginRedirectUrl)); + res.type("html").send(renderGlobalLogoutPage(getFrontchannelLogoutUrls(), logoutUrl.toString())); })); app.get("/api/me", (req, res) => { @@ -949,9 +961,8 @@ function normalizeLogoutUrl(value) { } } -function renderGlobalLogoutPage(frontchannelLogoutUrls, identityProviderLogoutUrl, finalRedirectUrl) { +function renderGlobalLogoutPage(frontchannelLogoutUrls, finalRedirectUrl) { const logoutUrlsJson = JSON.stringify(frontchannelLogoutUrls); - const identityProviderLogoutUrlJson = JSON.stringify(identityProviderLogoutUrl); const redirectUrlJson = JSON.stringify(finalRedirectUrl); return ` @@ -989,7 +1000,6 @@ function renderGlobalLogoutPage(frontchannelLogoutUrls, identityProviderLogoutUr localStorage.setItem("nodedc:platform-session-event", JSON.stringify(eventPayload)); } catch {} const logoutUrls = ${logoutUrlsJson}; - const identityProviderLogoutUrl = ${identityProviderLogoutUrlJson}; const finalRedirectUrl = ${redirectUrlJson}; for (const logoutUrl of logoutUrls) { fetch(logoutUrl, { mode: "no-cors", credentials: "include", keepalive: true }).catch(() => undefined); @@ -997,21 +1007,6 @@ function renderGlobalLogoutPage(frontchannelLogoutUrls, identityProviderLogoutUr image.referrerPolicy = "no-referrer"; image.src = logoutUrl; } - if (identityProviderLogoutUrl) { - fetch(identityProviderLogoutUrl, { mode: "no-cors", credentials: "include", keepalive: true }).catch(() => undefined); - const iframe = document.createElement("iframe"); - iframe.title = "NODE.DC identity logout"; - iframe.tabIndex = -1; - iframe.setAttribute("aria-hidden", "true"); - iframe.style.position = "fixed"; - iframe.style.width = "0"; - iframe.style.height = "0"; - iframe.style.opacity = "0"; - iframe.style.pointerEvents = "none"; - iframe.style.border = "0"; - iframe.src = identityProviderLogoutUrl; - document.body.appendChild(iframe); - } window.setTimeout(() => window.location.replace(finalRedirectUrl), 1200); @@ -1459,6 +1454,17 @@ function buildLoginRedirectUrl(returnTo, { forceLogin = false } = {}) { return loginUrl.toString(); } +function buildLoggedOutRedirectUrl(returnTo = "/") { + const loggedOutUrl = new URL("/auth/logged-out", config.appBaseUrl); + const cleanReturnTo = sanitizeReturnTo(returnTo); + + if (cleanReturnTo !== "/") { + loggedOutUrl.searchParams.set("returnTo", cleanReturnTo); + } + + return loggedOutUrl.toString(); +} + function randomBase64Url(size) { return randomBytes(size).toString("base64url"); }