Password-based Authentication
Password-based authentication block for React Single Page Applications
Installation
Folder structure
1import { cn } from '@/lib/utils'
2import { createClient } from '@/lib/supabase/client'
3import { Button } from '@/components/ui/button'
4import {
5 Card,
6 CardContent,
7 CardDescription,
8 CardHeader,
9 CardTitle,
10} from '@/components/ui/card'
11import { Input } from '@/components/ui/input'
12import { Label } from '@/components/ui/label'
13import { useState } from 'react'
14
15export function ForgotPasswordForm({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {
16 const [email, setEmail] = useState('')
17 const [error, setError] = useState<string | null>(null)
18 const [success, setSuccess] = useState(false)
19 const [isLoading, setIsLoading] = useState(false)
20
21 const handleForgotPassword = async (e: React.FormEvent) => {
22 const supabase = createClient()
23 e.preventDefault()
24 setIsLoading(true)
25 setError(null)
26
27 try {
28 // The url which will be included in the email. This URL needs to be configured in your redirect URLs in the Supabase dashboard at https://supabase.com/dashboard/project/_/auth/url-configuration
29 const { error } = await supabase.auth.resetPasswordForEmail(email, {
30 redirectTo: 'http://localhost:3000/update-password',
31 })
32 if (error) throw error
33 setSuccess(true)
34 } catch (error: unknown) {
35 setError(error instanceof Error ? error.message : 'An error occurred')
36 } finally {
37 setIsLoading(false)
38 }
39 }
40
41 return (
42 <div className={cn('flex flex-col gap-6', className)} {...props}>
43 {success ? (
44 <Card>
45 <CardHeader>
46 <CardTitle className="text-2xl">Check Your Email</CardTitle>
47 <CardDescription>Password reset instructions sent</CardDescription>
48 </CardHeader>
49 <CardContent>
50 <p className="text-sm text-muted-foreground">
51 If you registered using your email and password, you will receive a password reset
52 email.
53 </p>
54 </CardContent>
55 </Card>
56 ) : (
57 <Card>
58 <CardHeader>
59 <CardTitle className="text-2xl">Reset Your Password</CardTitle>
60 <CardDescription>
61 Type in your email and we'll send you a link to reset your password
62 </CardDescription>
63 </CardHeader>
64 <CardContent>
65 <form onSubmit={handleForgotPassword}>
66 <div className="flex flex-col gap-6">
67 <div className="grid gap-2">
68 <Label htmlFor="email">Email</Label>
69 <Input
70 id="email"
71 type="email"
72 placeholder="m@example.com"
73 required
74 value={email}
75 onChange={(e) => setEmail(e.target.value)}
76 />
77 </div>
78 {error && <p className="text-sm text-red-500">{error}</p>}
79 <Button type="submit" className="w-full" disabled={isLoading}>
80 {isLoading ? 'Sending...' : 'Send reset email'}
81 </Button>
82 </div>
83 <div className="mt-4 text-center text-sm">
84 Already have an account?{' '}
85 <a href="/login" className="underline underline-offset-4">
86 Login
87 </a>
88 </div>
89 </form>
90 </CardContent>
91 </Card>
92 )}
93 </div>
94 )
95}
Usage
Once you install the block in your React project, you'll get all the necessary pages and components to set up a password-based authentication flow.
Getting started
First, add a .env
file to your project with the following environment variables:
VITE_SUPABASE_URL=
VITE_SUPABASE_ANON_KEY=
-
If you're using supabase.com, you can find these values in the Connect modal under App Frameworks or in your project's API settings.
-
If you're using a local instance of Supabase, you can find these values by running
supabase start
orsupabase status
(if you already have it running).
Setting up routes and redirect URLs
-
Set the site URL in the URL Configuration settings in the Supabase Dashboard.
-
Set up the route users will visit to reset or update their password. Go to the URL Configuration settings and add the
forgot-password
route to the list of Redirect URLs. It should look something like:http://example.com/auth/forgot-password
. -
Update the redirect paths in the
login.tsx
andupdate-password.tsx
components to point to the logged-in routes in your app. -
Add the following code in the authenticated route to redirect to login if the user is unauthenticated.
import { useEffect } from "react"
import { createClient } from "@supabase/supabase-js"
export default function AuthenticatedRoute() {
useEffect(() => {
const checkAuth = async () => {
const client = createClient()
const { error } = await client.auth.getUser()
if (error) {
location.href = "/login"
}
}
checkAuth()
}, [])
return <div>Authenticated page</div>;
}