From 01739a50cd2de3027d6ba9f8bd0867b4488745da Mon Sep 17 00:00:00 2001 From: christiankrag Date: Sat, 13 Dec 2025 12:40:05 +0100 Subject: [PATCH] Switch from magic link to password-based authentication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update signup page with password and confirm password fields - Update login page with password field - Remove magic link/OTP flow entirely - Auto-redirect to dashboard after successful auth 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/app/(auth)/login/page.tsx | 59 ++++++++++--------------- src/app/(auth)/signup/page.tsx | 79 +++++++++++++++++++--------------- 2 files changed, 67 insertions(+), 71 deletions(-) diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx index 8ce28af..d765cea 100644 --- a/src/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -2,17 +2,19 @@ import { useState } from 'react' import Link from 'next/link' +import { useRouter } from 'next/navigation' import { createClient } from '@/lib/supabase/client' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' -import { Bot, Loader2, Mail } from 'lucide-react' +import { Bot, Loader2 } from 'lucide-react' export default function LoginPage() { + const router = useRouter() const [email, setEmail] = useState('') + const [password, setPassword] = useState('') const [isLoading, setIsLoading] = useState(false) - const [isSent, setIsSent] = useState(false) const [error, setError] = useState(null) const handleLogin = async (e: React.FormEvent) => { @@ -22,11 +24,9 @@ export default function LoginPage() { const supabase = createClient() - const { error } = await supabase.auth.signInWithOtp({ + const { error } = await supabase.auth.signInWithPassword({ email, - options: { - emailRedirectTo: `${window.location.origin}/auth/callback`, - }, + password, }) if (error) { @@ -35,34 +35,7 @@ export default function LoginPage() { return } - setIsSent(true) - setIsLoading(false) - } - - if (isSent) { - return ( -
- - -
- -
- Check your email - - We sent a magic link to {email} - -
- - Click the link in your email to sign in. If you don't see it, check your spam folder. - - - - -
-
- ) + router.push('/dashboard') } return ( @@ -74,7 +47,7 @@ export default function LoginPage() { Mylder Welcome back - Sign in to your account with a magic link + Sign in to your account
@@ -90,6 +63,18 @@ export default function LoginPage() { disabled={isLoading} /> +
+ + setPassword(e.target.value)} + required + disabled={isLoading} + /> +
{error && (

{error}

)} @@ -99,10 +84,10 @@ export default function LoginPage() { {isLoading ? ( <> - Sending link... + Signing in... ) : ( - 'Send Magic Link' + 'Sign In' )}

diff --git a/src/app/(auth)/signup/page.tsx b/src/app/(auth)/signup/page.tsx index 53d22c5..a323c13 100644 --- a/src/app/(auth)/signup/page.tsx +++ b/src/app/(auth)/signup/page.tsx @@ -2,31 +2,45 @@ import { useState } from 'react' import Link from 'next/link' +import { useRouter } from 'next/navigation' import { createClient } from '@/lib/supabase/client' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card' -import { Bot, Loader2, Mail } from 'lucide-react' +import { Bot, Loader2 } from 'lucide-react' export default function SignupPage() { + const router = useRouter() const [email, setEmail] = useState('') const [fullName, setFullName] = useState('') + const [password, setPassword] = useState('') + const [confirmPassword, setConfirmPassword] = useState('') const [isLoading, setIsLoading] = useState(false) - const [isSent, setIsSent] = useState(false) const [error, setError] = useState(null) const handleSignup = async (e: React.FormEvent) => { e.preventDefault() - setIsLoading(true) setError(null) + if (password !== confirmPassword) { + setError('Passwords do not match') + return + } + + if (password.length < 6) { + setError('Password must be at least 6 characters') + return + } + + setIsLoading(true) + const supabase = createClient() - const { error } = await supabase.auth.signInWithOtp({ + const { error } = await supabase.auth.signUp({ email, + password, options: { - emailRedirectTo: `${window.location.origin}/auth/callback`, data: { full_name: fullName, }, @@ -39,34 +53,7 @@ export default function SignupPage() { return } - setIsSent(true) - setIsLoading(false) - } - - if (isSent) { - return ( -

- - -
- -
- Check your email - - We sent a magic link to {email} - -
- - Click the link in your email to complete your signup. If you don't see it, check your spam folder. - - - - -
-
- ) + router.push('/dashboard') } return ( @@ -106,6 +93,30 @@ export default function SignupPage() { disabled={isLoading} /> +
+ + setPassword(e.target.value)} + required + disabled={isLoading} + /> +
+
+ + setConfirmPassword(e.target.value)} + required + disabled={isLoading} + /> +
{error && (

{error}

)} @@ -118,7 +129,7 @@ export default function SignupPage() { Creating account... ) : ( - 'Get Started Free' + 'Create Account' )}