I have been struggling with my reset password flow in my NextJS (14) app using Supebase auth.
See documentation here: https://supabase.com/docs/reference/javascript/auth-resetpasswordforemail
I got the resetPasswordForEmail to work but;
- The env variabeles wont expose on the front-end. That is needed to follow the documentation and create a clientside Supabase client.
- To test if it would work if I had access to the .env variables I hardcoded the NEXT_SUPABASE_URL and NEXT_SUPABASE_ANON_KEY in the code. It works then.
- Regardless of whether I manage to expose these variables clientside, I think this would be undesirable as I don’t want to expose them.
Regarding the exposing of the .env variables; I did prefix them with NEXT_PUBLIC_ and rebuild the app before running it again. Did not work.
How to manage the reset password without exposing supabase secrets to the client side?
My resetPasswordForm
'use client'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { useEffect, useState } from 'react'
import { useFormState } from 'react-dom'
import { resetPassword } from './action'
import SubmitButton from '@/app/(loggedIn)/components/submitbutton'
import { initialState } from '@/utils'
import { createBrowserClient } from '@supabase/ssr'
import { Database } from '@/types/supabase'
const url = 'https://xyz.supabase.co'
const key =
'xyzxyz'
const ResetPasswordForm = () => {
const [formState, formAction] = useFormState(resetPassword, initialState)
console.log(key, url)
const supabase = createBrowserClient(url!, key!)
useEffect(() => {
supabase.auth.onAuthStateChange((event, session) => {
console.log(event, session)
})
})
return (
<>
<form action={formAction} className='w-[300px]'>
<Label htmlFor='password'>New password</Label>
<Input
type='password'
id='password'
name='password'
required
className='my-4'
/>
<SubmitButton going='Updating' normal='Update password' />
</form>
</>
)
}
export default ResetPasswordForm
Reset password page
import Header from '@/components/header'
import ResetPasswordForm from './reset-form'
const ResetPassword = async () => {
return (
<>
<Header title='Reset password' />
<ResetPasswordForm />
</>
)
}
export default ResetPassword
Resetpassword action
'use server'
import { createClient as createSupabaseClient } from '@/utils/supabase/server'
import { resetPasswordSchema } from './schema'
export const resetPassword = async (prevData: any, formData: FormData) => {
const validatedFields = resetPasswordSchema.safeParse({
password: formData.get('password'),
})
if (!validatedFields.success) {
return {
status: 'error',
errors: validatedFields.error.flatten().fieldErrors,
}
}
const supabase = createSupabaseClient()
const { error } = await supabase.auth.updateUser({
password: validatedFields.data.password,
})
if (error) {
console.log(error)
return {
status: 'error',
message: 'An error occurred while resetting your password',
}
}
console.log('Password reset successfully')
return {
status: 'success',
message: 'Password reset successfully',
}
}