Short answer
With Confirm Email on, which is the default on hosted Supabase projects, users have to click the link in the confirmation email before their first sign-in. If they never got the email, check sending first: the default email service allows 2 emails per hour on a best-effort basis, so set up custom SMTP for production. Make sure the link goes to your real site rather than localhost:3000, then resend the confirmation with supabase.auth.resend().
Why it happens, and the fix
01
The user hasn’t clicked the confirmation link
“Signing in is not allowed for this user as the email address is not confirmed.” Supabase, Auth error codes
With Confirm Email on, a new user has to confirm their address before their first sign-in, and Supabase rejects the sign-in until they do. Tell users to check their inbox after signing up, and handle email_not_confirmed with a clear message and a resend button.
02
It worked locally, then failed on the hosted project
“On hosted Supabase projects, this is true by default. On self-hosted projects or in local development, this is false by default.” Supabase, Password-based Auth
Email confirmation is on by default for hosted projects and off by default locally, so sign-in can work in development and fail after you deploy. The setting is on the Auth Providers page for hosted projects.
03
The confirmation email never arrived
“The service has a rate limit of 2 emails per hour, and availability is on a best-effort basis.” Supabase, Password-based Auth
The signup confirmation needs an SMTP server to send it. Supabase’s default email service is for trying things out, so configure a custom SMTP server for production.
04
The link opened localhost:3000
“If you don't specify a redirect URL, the user is automatically redirected to your site URL. This defaults to localhost:3000, but you can also configure this.” Supabase, Password-based Auth
Without a redirect URL in signUp(), the link goes to your Site URL, which defaults to localhost:3000. Set the Site URL to your live site, and add any redirect URL you pass to the Redirect URLs list.
05
Send the confirmation again
“Resends an existing signup confirmation email, email change email, SMS OTP or phone change OTP.” Supabase, JavaScript: resend
Once sending and the links work, users who signed up earlier still need a new email. supabase.auth.resend() with type signup sends it again.
const { error } = await supabase.auth.resend({ type: 'signup', email: 'email@example.com', options: { emailRedirectTo: 'https://example.com/welcome' } })
Checked against the vendor’s docs on : Supabase docs: Auth error codes; Supabase docs: Password-based Auth; Supabase docs: Auth general configuration; Supabase docs: JavaScript resend.
Rather hand it over?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
- from $450App Fix TicketOne reproducible bug in an existing mobile or web app, diagnosed and fixed.See scope and start
- from $450AI-Built App RescueA Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way.See scope and start
Related: Supabase email rate limit exceeded · Supabase auth emails going to spam · Supabase auth emails link to localhost · Supabase public storage bucket