From 4588cfda4d259d336e4d5d55a1d74cad864852e0 Mon Sep 17 00:00:00 2001 From: Usama Sadiq Date: Tue, 14 Jul 2026 21:08:39 +0500 Subject: [PATCH] Preserve returnToPath across SSO proxy-login redirect The MCP OAuth /authorize page was lost during the SSO round-trip because returnToPath lived only in a Jotai atom destroyed by the full-page navigation to /auth/sso/proxy-login. Thread it as a query parameter so the controller can redirect back after setting the JWT cookie. --- .../twenty-front/src/pages/auth/SignInUp.tsx | 18 ++++++++++++++++-- .../controllers/sso-proxy-login.controller.ts | 12 +++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/twenty-front/src/pages/auth/SignInUp.tsx b/packages/twenty-front/src/pages/auth/SignInUp.tsx index 8c261f298324b..4819abe72579a 100644 --- a/packages/twenty-front/src/pages/auth/SignInUp.tsx +++ b/packages/twenty-front/src/pages/auth/SignInUp.tsx @@ -95,9 +95,23 @@ export const SignInUp = () => { // served separately from the backend. In the unified-image setup // both share an origin and the absolute URL collapses to the same // path; in split-deploy mode it correctly hits the API. - window.location.replace( - `${REACT_APP_SERVER_BASE_URL}/auth/sso/proxy-login`, + // + // Thread returnToPath so the server can redirect back after setting + // the JWT cookie -- without this, navigating to /authorize (MCP + // OAuth consent) would land the user on the dashboard instead of + // returning to the consent screen after SSO. + const returnToPath = + window.location.pathname + window.location.search + window.location.hash; + const proxyUrl = new URL( + '/auth/sso/proxy-login', + REACT_APP_SERVER_BASE_URL || window.location.origin, ); + + if (returnToPath && returnToPath !== '/') { + proxyUrl.searchParams.set('returnToPath', returnToPath); + } + + window.location.replace(proxyUrl.toString()); } }, [isSsoEnabled]); diff --git a/packages/twenty-server/src/engine/core-modules/auth/controllers/sso-proxy-login.controller.ts b/packages/twenty-server/src/engine/core-modules/auth/controllers/sso-proxy-login.controller.ts index 1f19e106f9ae1..e2745ff19b59b 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/controllers/sso-proxy-login.controller.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/controllers/sso-proxy-login.controller.ts @@ -133,7 +133,17 @@ export class SsoProxyLoginController { }, }); - return res.redirect(HttpStatus.FOUND, '/'); + // Honour returnToPath so callers like the MCP OAuth /authorize page + // can survive the SSO round-trip. Validate that the value is a + // same-origin path (starts with exactly one `/`) to prevent open + // redirect attacks via protocol-relative URLs (`//evil.com`). + const returnToPath = req.query.returnToPath as string | undefined; + const destination = + returnToPath?.startsWith('/') && !returnToPath.startsWith('//') + ? returnToPath + : '/'; + + return res.redirect(HttpStatus.FOUND, destination); } private resolveEmail(