From 9b679a4db21aa1724c049c497e788279f5d0d379 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Sat, 28 Feb 2026 18:25:10 +0100 Subject: [PATCH] fix: harden auth form sign-in flow and redirect reliability --- src/components/auth/LoginForm.tsx | 38 +++++++++++++++++++++------- src/components/auth/RegisterForm.tsx | 15 ++++++++--- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/components/auth/LoginForm.tsx b/src/components/auth/LoginForm.tsx index 918a27c..ce98eb5 100644 --- a/src/components/auth/LoginForm.tsx +++ b/src/components/auth/LoginForm.tsx @@ -3,7 +3,9 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; import { signIn } from "next-auth/react"; +import { ErrorMessage } from "@/components/ui/ErrorMessage"; import { useTranslate } from "@/hooks/useTranslate"; +import type { AppErrorType } from "@/types/global"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Button } from "@/components/ui/button"; @@ -16,9 +18,17 @@ interface LoginFormProps { export function LoginForm({ from }: LoginFormProps) { const router = useRouter(); const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); + const [error, setError] = useState(null); const { t } = useTranslate(); + const getSafeRedirectPath = (path?: string) => { + if (!path || !path.startsWith("/") || path.startsWith("//")) { + return "/"; + } + + return path; + }; + const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); setIsLoading(true); @@ -37,14 +47,24 @@ export function LoginForm({ from }: LoginFormProps) { redirect: false, }); - if (result?.error) { - setError("Email ou mot de passe incorrect"); - } else { - router.push(from || "/"); - router.refresh(); + if (!result || result.error || !result.ok) { + setError({ + code: "AUTH_INVALID_CREDENTIALS", + name: "Login failed", + message: "Email ou mot de passe incorrect", + }); + return; } - } catch (_error) { - setError("Une erreur est survenue lors de la connexion : " + _error); + + const redirectPath = getSafeRedirectPath(from); + window.location.assign(redirectPath); + router.refresh(); + } catch { + setError({ + code: "AUTH_FETCH_ERROR", + name: "Login error", + message: "Une erreur est survenue lors de la connexion", + }); } finally { setIsLoading(false); } @@ -80,7 +100,7 @@ export function LoginForm({ from }: LoginFormProps) { {t("login.form.remember")} - {error &&
{error}
} + {error && } diff --git a/src/components/auth/RegisterForm.tsx b/src/components/auth/RegisterForm.tsx index 9f18ecd..91f9a22 100644 --- a/src/components/auth/RegisterForm.tsx +++ b/src/components/auth/RegisterForm.tsx @@ -15,12 +15,20 @@ interface RegisterFormProps { from?: string; } -export function RegisterForm({ from: _from }: RegisterFormProps) { +export function RegisterForm({ from }: RegisterFormProps) { const router = useRouter(); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const { t } = useTranslate(); + const getSafeRedirectPath = (path?: string) => { + if (!path || !path.startsWith("/") || path.startsWith("//")) { + return "/"; + } + + return path; + }; + const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); setIsLoading(true); @@ -61,14 +69,15 @@ export function RegisterForm({ from: _from }: RegisterFormProps) { redirect: false, }); - if (signInResult?.error) { + if (!signInResult || signInResult.error || !signInResult.ok) { setError({ code: "AUTH_INVALID_CREDENTIALS", name: "Login failed", message: "Inscription réussie mais erreur lors de la connexion automatique", }); } else { - router.push("/"); + const redirectPath = getSafeRedirectPath(from); + window.location.assign(redirectPath); router.refresh(); } } catch {