From 0c1a64d47dd2aa41ed55cdd3a762c4d8e636e2d9 Mon Sep 17 00:00:00 2001 From: Stavros Date: Sat, 18 Jul 2026 17:05:52 +0300 Subject: [PATCH] fix: make login_for optional --- .../components/quick-actions/quick-actions.tsx | 10 ++++++++-- frontend/src/lib/hooks/login-for.ts | 8 ++++++-- frontend/src/lib/hooks/screen-params.ts | 14 ++++---------- frontend/src/pages/authorize-page.tsx | 10 ++++++++-- frontend/src/pages/continue-page.tsx | 12 +++++++++--- frontend/src/pages/forgot-password-page.tsx | 12 +++++++++--- frontend/src/pages/login-page.tsx | 15 +++++++++------ frontend/src/pages/logout-page.tsx | 10 ++++++++-- frontend/src/pages/totp-page.tsx | 12 +++++++++--- 9 files changed, 70 insertions(+), 33 deletions(-) diff --git a/frontend/src/components/quick-actions/quick-actions.tsx b/frontend/src/components/quick-actions/quick-actions.tsx index c141f616..cc33b2f4 100644 --- a/frontend/src/components/quick-actions/quick-actions.tsx +++ b/frontend/src/components/quick-actions/quick-actions.tsx @@ -32,8 +32,8 @@ import { useTranslation } from "react-i18next"; import { useLocation } from "react-router"; import { useRef } from "react"; import { + searchParamsFromObject, useScreenParams, - recompileScreenParams, } from "@/lib/hooks/screen-params"; import { useMutation } from "@tanstack/react-query"; import axios from "axios"; @@ -70,7 +70,13 @@ export const QuickActions = () => { const redirectTimer = useRef(null); const searchParams = new URLSearchParams(search); const screenParams = useScreenParams(searchParams); - const compiledParams = recompileScreenParams(screenParams); + const compiledParams = (() => { + const params = searchParamsFromObject(screenParams).toString(); + if (params.length > 0) { + return `?${params}`; + } + return ""; + })(); const [isOpen, setIsOpen] = useState(false); diff --git a/frontend/src/lib/hooks/login-for.ts b/frontend/src/lib/hooks/login-for.ts index 8cf11579..b106c5d7 100644 --- a/frontend/src/lib/hooks/login-for.ts +++ b/frontend/src/lib/hooks/login-for.ts @@ -1,10 +1,11 @@ type UseLoginForProps = { login_for?: "oidc" | "app"; - compiledParams: string; + params: URLSearchParams; }; export const useLoginFor = (props: UseLoginForProps): string => { - const { login_for, compiledParams } = props; + const { login_for, params } = props; + const compiledParams = params.toString() ? "?" + params.toString() : ""; switch (login_for) { case "oidc": @@ -12,6 +13,9 @@ export const useLoginFor = (props: UseLoginForProps): string => { case "app": return "/continue" + compiledParams; default: + if (params.get("redirect_uri")) { + return "/continue" + compiledParams + } return "/logout"; } }; diff --git a/frontend/src/lib/hooks/screen-params.ts b/frontend/src/lib/hooks/screen-params.ts index abf3a41a..05e4b748 100644 --- a/frontend/src/lib/hooks/screen-params.ts +++ b/frontend/src/lib/hooks/screen-params.ts @@ -27,16 +27,10 @@ export function useScreenParams(params: URLSearchParams): ScreenParams { return parsed.data; } -export function recompileScreenParams(params: ScreenParams): string { - const p = new URLSearchParams( +export function searchParamsFromObject(obj: Object): URLSearchParams { + return new URLSearchParams( Object.fromEntries( - Object.entries(params).filter(([, v]) => v !== undefined), + Object.entries(obj).filter(([, v]) => v !== undefined), ) as Record, - ).toString(); - - if (p.length > 0) { - return "?" + p; - } - - return ""; + ); } diff --git a/frontend/src/pages/authorize-page.tsx b/frontend/src/pages/authorize-page.tsx index 0f14a583..17aa3df7 100644 --- a/frontend/src/pages/authorize-page.tsx +++ b/frontend/src/pages/authorize-page.tsx @@ -22,7 +22,7 @@ import { TooltipTrigger, } from "@/components/ui/tooltip"; import { - recompileScreenParams, + searchParamsFromObject, useScreenParams, } from "@/lib/hooks/screen-params"; import { useEffect } from "react"; @@ -89,7 +89,13 @@ export const AuthorizePage = () => { const searchParams = new URLSearchParams(search); const screenParams = useScreenParams(searchParams); const isOidc = screenParams.login_for === "oidc"; - const compiledParams = recompileScreenParams(screenParams); + const compiledParams = (() => { + const params = searchParamsFromObject(screenParams).toString(); + if (params.length > 0) { + return `?${params}`; + } + return ""; + })(); // TODO: maybe a better way to do this const shouldAutoAuthorize = diff --git a/frontend/src/pages/continue-page.tsx b/frontend/src/pages/continue-page.tsx index a4e34fc5..7b7cdb72 100644 --- a/frontend/src/pages/continue-page.tsx +++ b/frontend/src/pages/continue-page.tsx @@ -13,7 +13,7 @@ import { Navigate, useLocation, useNavigate } from "react-router"; import { useCallback, useEffect, useRef, useState } from "react"; import { useRedirectUri } from "@/lib/hooks/redirect-uri"; import { - recompileScreenParams, + searchParamsFromObject, useScreenParams, } from "@/lib/hooks/screen-params"; @@ -32,7 +32,13 @@ export const ContinuePage = () => { const screenParams = useScreenParams(searchParams); const redirectUri = screenParams.redirect_uri; const isAppLogin = screenParams.login_for === "app"; - const recompiledParams = recompileScreenParams(screenParams); + const compiledParams = (() => { + const params = searchParamsFromObject(screenParams).toString(); + if (params.length > 0) { + return `?${params}`; + } + return ""; + })(); const { url, valid, trusted, allowedProto, httpsDowngrade } = useRedirectUri( redirectUri, @@ -89,7 +95,7 @@ export const ContinuePage = () => { }, [shouldAutoRedirect, redirectToTarget]); if (!auth.authenticated) { - return ; + return ; } if (!hasValidRedirect || !isAppLogin) { diff --git a/frontend/src/pages/forgot-password-page.tsx b/frontend/src/pages/forgot-password-page.tsx index 58b80a3a..8052701e 100644 --- a/frontend/src/pages/forgot-password-page.tsx +++ b/frontend/src/pages/forgot-password-page.tsx @@ -12,8 +12,8 @@ import { useTranslation } from "react-i18next"; import Markdown from "react-markdown"; import { useLocation } from "react-router"; import { - recompileScreenParams, - useScreenParams, + searchParamsFromObject, + useScreenParams, } from "@/lib/hooks/screen-params"; export const ForgotPasswordPage = () => { @@ -22,7 +22,13 @@ export const ForgotPasswordPage = () => { const { search } = useLocation(); const searchParams = new URLSearchParams(search); const screenParams = useScreenParams(searchParams); - const compiledParams = recompileScreenParams(screenParams); + const compiledParams = (() => { + const params = searchParamsFromObject(screenParams).toString(); + if (params.length > 0) { + return `?${params}`; + } + return ""; + })(); return ( diff --git a/frontend/src/pages/login-page.tsx b/frontend/src/pages/login-page.tsx index ab63c72a..08218e00 100644 --- a/frontend/src/pages/login-page.tsx +++ b/frontend/src/pages/login-page.tsx @@ -26,7 +26,7 @@ import { useTranslation } from "react-i18next"; import { Navigate, useLocation } from "react-router"; import { toast } from "sonner"; import { - recompileScreenParams, + searchParamsFromObject, useScreenParams, } from "@/lib/hooks/screen-params"; import { useLoginFor } from "@/lib/hooks/login-for"; @@ -63,13 +63,16 @@ export const LoginPage = () => { const searchParams = new URLSearchParams(search); const screenParams = useScreenParams(searchParams); - const compiledParams = recompileScreenParams({ - ...screenParams, - oidc_prompt: undefined, - }); + const compiledParams = (() => { + const params = searchParamsFromObject(screenParams).toString(); + if (params.length > 0) { + return `?${params}`; + } + return ""; + })(); const loginForUrl = useLoginFor({ login_for: screenParams.login_for, - compiledParams, + params: searchParamsFromObject({ ...screenParams, oidc_prompt: undefined}), }); const [isOauthAutoRedirect, setIsOauthAutoRedirect] = useState( diff --git a/frontend/src/pages/logout-page.tsx b/frontend/src/pages/logout-page.tsx index d1a734b9..78ef0555 100644 --- a/frontend/src/pages/logout-page.tsx +++ b/frontend/src/pages/logout-page.tsx @@ -17,8 +17,8 @@ import { type UseMutationResult } from "@tanstack/react-query"; import { type AxiosResponse } from "axios"; import { useLocation } from "react-router"; import { + searchParamsFromObject, useScreenParams, - recompileScreenParams, } from "@/lib/hooks/screen-params"; export const LogoutPage = () => { @@ -29,7 +29,13 @@ export const LogoutPage = () => { const redirectTimer = useRef(null); const searchParams = new URLSearchParams(search); const screenParams = useScreenParams(searchParams); - const compiledParams = recompileScreenParams(screenParams); + const compiledParams = (() => { + const params = searchParamsFromObject(screenParams).toString(); + if (params.length > 0) { + return `?${params}`; + } + return ""; + })(); const logoutMutation = useMutation({ mutationFn: () => axios.post("/api/user/logout"), diff --git a/frontend/src/pages/totp-page.tsx b/frontend/src/pages/totp-page.tsx index e66b4704..3b9a6ef7 100644 --- a/frontend/src/pages/totp-page.tsx +++ b/frontend/src/pages/totp-page.tsx @@ -17,7 +17,7 @@ import { useTranslation } from "react-i18next"; import { Navigate, useLocation } from "react-router"; import { toast } from "sonner"; import { - recompileScreenParams, + searchParamsFromObject, useScreenParams, } from "@/lib/hooks/screen-params"; import { useLoginFor } from "@/lib/hooks/login-for"; @@ -32,10 +32,16 @@ export const TotpPage = () => { const searchParams = new URLSearchParams(search); const screenParams = useScreenParams(searchParams); - const compiledParams = recompileScreenParams(screenParams); + const compiledParams = (() => { + const params = searchParamsFromObject(screenParams).toString(); + if (params.length > 0) { + return `?${params}`; + } + return ""; + })(); const loginForUrl = useLoginFor({ login_for: screenParams.login_for, - compiledParams, + params: searchParamsFromObject(screenParams), }); const totpMutation = useMutation({