diff --git a/src/app/(auth)/verify-email/page.tsx b/src/app/(auth)/verify-email/page.tsx index d7ea66f3..a06dccc8 100644 --- a/src/app/(auth)/verify-email/page.tsx +++ b/src/app/(auth)/verify-email/page.tsx @@ -13,6 +13,7 @@ const VerifyEmailContent = () => { const searchParams = useSearchParams(); const verifyEmail = useVerifyEmail(); const [status, setStatus] = useState<"loading" | "success" | "error">("loading"); + const [errorMessage, setErrorMessage] = useState(null); const hasAttempted = useRef(false); useEffect(() => { // Prevent multiple attempts @@ -25,6 +26,7 @@ const VerifyEmailContent = () => { if (!userId || (!secret && !token)) { setStatus("error"); + setErrorMessage("Missing verification parameters in the URL."); return; } @@ -38,10 +40,12 @@ const VerifyEmailContent = () => { setStatus("success"); } else { setStatus("error"); + setErrorMessage('error' in data ? String(data.error) : "Verification failed. The link might be invalid or expired."); } }, - onError: () => { + onError: (error) => { setStatus("error"); + setErrorMessage(error.message || "An unexpected error occurred during verification."); }, } ); @@ -97,15 +101,24 @@ const VerifyEmailContent = () => { Verification Failed - The verification link is invalid or has expired. Please try requesting a new verification email. + {errorMessage || "The verification link is invalid or has expired. Please try requesting a new verification email."} - + diff --git a/src/features/auth/api/use-verify-email.ts b/src/features/auth/api/use-verify-email.ts index e64f0aff..d9193755 100644 --- a/src/features/auth/api/use-verify-email.ts +++ b/src/features/auth/api/use-verify-email.ts @@ -31,7 +31,16 @@ export const useVerifyEmail = () => { const mutation = useMutation({ mutationFn: async ({ json }) => { const response = await client.api.auth["verify-email"].$post({ json }); - return await response.json(); + const data = await response.json(); + + if (!response.ok) { + const errorMsg = 'error' in data ? String(data.error) : + 'message' in data ? String(data.message) : + "Verification failed"; + throw new Error(errorMsg); + } + + return data; }, onSuccess: (data) => { if ('success' in data && data.success) { diff --git a/src/features/auth/server/route.ts b/src/features/auth/server/route.ts index 72394401..d4d02988 100644 --- a/src/features/auth/server/route.ts +++ b/src/features/auth/server/route.ts @@ -138,7 +138,7 @@ const app = new Hono() setCookie(c, AUTH_COOKIE, session.secret, { path: "/", httpOnly: true, - secure: process.env.NODE_ENV === "production", + secure: process.env.NODE_ENV === "production" || c.req.header("x-forwarded-proto") === "https", sameSite: "lax", maxAge: 60 * 60 * 24 * 30, }); @@ -746,6 +746,7 @@ const app = new Hono() */ .post("/verify-email", zValidator("json", verifyEmailSchema), async (c) => { const { userId, secret } = c.req.valid("json"); + console.log(`[Auth] Verifying email for user: ${userId}, secret length: ${secret?.length || 0}`); try { // Create a lightweight client without admin credentials because verification @@ -798,7 +799,7 @@ const app = new Hono() setCookie(c, AUTH_COOKIE, session.secret, { path: "/", httpOnly: true, - secure: process.env.NODE_ENV === "production", + secure: process.env.NODE_ENV === "production" || c.req.header("x-forwarded-proto") === "https", sameSite: "lax", maxAge: 60 * 60 * 24 * 30, // 30 days }); @@ -815,6 +816,7 @@ const app = new Hono() autoAuthenticated: true, }); } catch (error: unknown) { + console.error("[Auth] Verification error:", error); const appwriteError = error as { code?: number; type?: string; message?: string }; // Handle specific verification errors @@ -1351,7 +1353,7 @@ const app = new Hono() setCookie(c, AUTH_COOKIE, session.secret, { path: "/", httpOnly: true, - secure: process.env.NODE_ENV === "production", + secure: process.env.NODE_ENV === "production" || c.req.header("x-forwarded-proto") === "https", sameSite: "lax", maxAge: 60 * 60 * 24 * 30, }); @@ -1443,7 +1445,7 @@ const app = new Hono() setCookie(c, AUTH_COOKIE, session.secret, { path: "/", httpOnly: true, - secure: process.env.NODE_ENV === "production", + secure: process.env.NODE_ENV === "production" || c.req.header("x-forwarded-proto") === "https", sameSite: "lax", maxAge: 60 * 60 * 24 * 30, // 30 days });