fix: harden auth form sign-in flow and redirect reliability
This commit is contained in:
@@ -3,7 +3,9 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { signIn } from "next-auth/react";
|
import { signIn } from "next-auth/react";
|
||||||
|
import { ErrorMessage } from "@/components/ui/ErrorMessage";
|
||||||
import { useTranslate } from "@/hooks/useTranslate";
|
import { useTranslate } from "@/hooks/useTranslate";
|
||||||
|
import type { AppErrorType } from "@/types/global";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -16,9 +18,17 @@ interface LoginFormProps {
|
|||||||
export function LoginForm({ from }: LoginFormProps) {
|
export function LoginForm({ from }: LoginFormProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<AppErrorType | null>(null);
|
||||||
const { t } = useTranslate();
|
const { t } = useTranslate();
|
||||||
|
|
||||||
|
const getSafeRedirectPath = (path?: string) => {
|
||||||
|
if (!path || !path.startsWith("/") || path.startsWith("//")) {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@@ -37,14 +47,24 @@ export function LoginForm({ from }: LoginFormProps) {
|
|||||||
redirect: false,
|
redirect: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result?.error) {
|
if (!result || result.error || !result.ok) {
|
||||||
setError("Email ou mot de passe incorrect");
|
setError({
|
||||||
} else {
|
code: "AUTH_INVALID_CREDENTIALS",
|
||||||
router.push(from || "/");
|
name: "Login failed",
|
||||||
router.refresh();
|
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 {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@@ -80,7 +100,7 @@ export function LoginForm({ from }: LoginFormProps) {
|
|||||||
{t("login.form.remember")}
|
{t("login.form.remember")}
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
{error && <div className="text-sm text-destructive">{error}</div>}
|
{error && <ErrorMessage errorCode={error.code} variant="form" />}
|
||||||
<Button type="submit" disabled={isLoading} className="w-full">
|
<Button type="submit" disabled={isLoading} className="w-full">
|
||||||
{isLoading ? t("login.form.submit.loading.login") : t("login.form.submit.login")}
|
{isLoading ? t("login.form.submit.loading.login") : t("login.form.submit.login")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -15,12 +15,20 @@ interface RegisterFormProps {
|
|||||||
from?: string;
|
from?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RegisterForm({ from: _from }: RegisterFormProps) {
|
export function RegisterForm({ from }: RegisterFormProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<AppErrorType | null>(null);
|
const [error, setError] = useState<AppErrorType | null>(null);
|
||||||
const { t } = useTranslate();
|
const { t } = useTranslate();
|
||||||
|
|
||||||
|
const getSafeRedirectPath = (path?: string) => {
|
||||||
|
if (!path || !path.startsWith("/") || path.startsWith("//")) {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@@ -61,14 +69,15 @@ export function RegisterForm({ from: _from }: RegisterFormProps) {
|
|||||||
redirect: false,
|
redirect: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (signInResult?.error) {
|
if (!signInResult || signInResult.error || !signInResult.ok) {
|
||||||
setError({
|
setError({
|
||||||
code: "AUTH_INVALID_CREDENTIALS",
|
code: "AUTH_INVALID_CREDENTIALS",
|
||||||
name: "Login failed",
|
name: "Login failed",
|
||||||
message: "Inscription réussie mais erreur lors de la connexion automatique",
|
message: "Inscription réussie mais erreur lors de la connexion automatique",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
router.push("/");
|
const redirectPath = getSafeRedirectPath(from);
|
||||||
|
window.location.assign(redirectPath);
|
||||||
router.refresh();
|
router.refresh();
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
Reference in New Issue
Block a user