Nothing is misconfigured. With Confirm email on, signUp creates the user and sends the email, but gives no session until they click the link. session: null is the success case here.
So change the flow:
const { data, error } = await supabase.auth.signUp({
email, password,
options: { emailRedirectTo: `${window.location.origin}/welcome` },
})
if (error) return setError(error.message)
if (!data.session) return setStep('check-your-inbox')
navigate('/dashboard')The 'User already registered' on the second try is simply because the first try worked.
One subtle thing: when someone signs up with an email that already exists and is confirmed, Supabase returns a user object with an empty identities array instead of an error, so attackers can't use signup to find out who has an account. Show the same 'check your inbox' message in that case too.