Demo, all content is generated
Question

Password reset email logs the user in but never shows the 'new password' form

Solved · 891 views · asked by jonah_b · edited

User clicks 'forgot password', gets the email, clicks the link, and ends up on my homepage logged in. There's a /reset-password page with a form but they never see it. So they're in, but still don't know their password, and next time same story.

My code:

await supabase.auth.resetPasswordForEmail(email)
What I’ve tried

Tried adding redirectTo: '/reset-password'. Then I got 'Invalid redirect URL' in the logs. Claude Code made a useEffect that checks for 'type=recovery' in the URL, but the URL doesn't have that.

Comment

3 answers

Marked as helpful by the asker
mira_dev · edited

Close. Three pieces:

  1. redirectTo must be a full URL, and on the Redirect URLs allow-list:
await supabase.auth.resetPasswordForEmail(email, {
  redirectTo: `${window.location.origin}/reset-password`,
})

Without that, Supabase sends people to the Site URL (your homepage) and they're just logged in, which is what you see.

  1. On /reset-password, listen for the recovery event instead of parsing the URL:
supabase.auth.onAuthStateChange((event) => {
  if (event === 'PASSWORD_RECOVERY') setShowForm(true)
})
  1. The form calls supabase.auth.updateUser({ password: newPassword }).
Comment
Full URL + allowlist fixed the redirect, event works. Thanks! jonah_b · edited
If you later move to SSR with @supabase/ssr, the link format changes (token_hash + type=recovery via verifyOtp). The idea stays the same. jb_supa · edited
pawel_z · edited

For local testing add http://localhost:3000/** to the Redirect URLs as well, otherwise it works in prod and not locally (or the other way around) and you'll think the code is flaky.

Comment
carmen_v · edited

Nice touch after the new password is saved: await supabase.auth.signOut({ scope: 'others' }). That ends sessions on other devices, which is usually what someone resetting a password wants.

Comment