Proxy Mail QA

Common Supabase sign-up and login problems, and how to fix them

Supabase Auth works out of the box for the person who set it up, then fails for the first tester: the email never arrives, the link says it has expired, or it opens but nobody is signed in. Most of these come down to a handful of settings and one rule about which browser opens the link.

Updated

Details below are from Supabase’s documentation on 23 October 2026. Check it for current limits and settings. For the basics, sending your first test emails and setting up a sender, start with Test Supabase Auth emails.

The email never arrives

The built-in sender won’t email your testers. Supabase’s own email service only delivers to members of your project’s team, at most 2 emails an hour. It works for you because you’re on the team, then refuses everyone else with “Email address not authorized”. Set up custom SMTP under Authentication, Emails.

Your SMTP provider is still in its sandbox. A new Resend account sends only to your own address until you verify a domain, and Amazon SES only to addresses you’ve verified. Supabase hands the email over, and the provider quietly drops it.

You asked again too soon. By default each user can get one confirmation, magic-link, code or reset email every 60 seconds, and each IP address can make 30 sign-up and sign-in requests every 5 minutes. A test that retries quickly, or a suite running from one CI machine, hits these and gets a 429. Raise them for your staging project under Authentication, Rate Limits.

The address already has an account. To avoid revealing who has signed up, Supabase answers a sign-up for a confirmed address as if it succeeded, with a user that has no identities, and sends no email. A test that reuses an address waits for an email that never comes. Use a fresh address for every run.

Confirm email is switched off. Then sign-up signs the user in at once and sends nothing. Check Authentication, Sign In / Providers, Email. It’s often turned off while building and never back on.

You click the link and land on your app with error_code=otp_expired (“Email link is invalid or has expired”) in the address bar.

It was opened in a different browser. With the PKCE flow, which Supabase’s server-side helpers use, the browser that started the sign-up keeps a secret the link needs. Open the link in another browser, a private window or another device, and the exchange fails, often as “both auth code and code verifier should be non-empty”. Testers should open the link in the browser they signed up in. For links that work anywhere, build them from {{ .TokenHash }} and verify them on your server with verifyOtp.

Nothing finishes the sign-in. The link lands on your app with a code (or a token) in the address, and some page has to exchange it for a session. If that route is missing, the person sees your home page, signed out. Check the link’s destination page calls exchangeCodeForSession, or verifyOtp with the token hash.

The server can’t see the session. The default link puts the session after a # in the address, which only the browser can read. Server-rendered apps need the token-hash link above.

The Site URL starts as http://localhost:3000, and any redirectTo that isn’t on the Redirect URLs list falls back to it. Set the Site URL to the deployed app and list every environment. More in why emails link to localhost; Proxy Mail QA flags those links on the address’s row.

Sign-up fails with “Database error saving new user”

Something in the database refused the new user, almost always a trigger on auth.users, such as one that creates a row in profiles. Common causes: the table or a column it writes to doesn’t exist, the function isn’t security definer and so can’t write to public, or a column it fills is not null and the sign-up didn’t send it. Supabase’s Auth and Postgres logs show the real error.

Test with awkward values too: a name with an apostrophe, another script or 255 characters can break a profile column that ordinary test data never reaches. Unusual names and passwords has a list to try.

The reset email arrives, but the password doesn’t change

A reset link signs the person in with a recovery session and fires the PASSWORD_RECOVERY event. Your app has to notice that, show a form for the new password and call updateUser with it. If it doesn’t, the person just ends up signed in, with their old password. With PKCE, the link must also be opened in the browser that asked for it. More in Test password reset emails.

Captcha blocks your automated tests

With captcha protection on (Authentication, Attack Protection), every sign-up and sign-in needs a captcha token, so an automated browser can’t get through. On your staging project, use your captcha provider’s test keys, which always pass, and keep the real keys for production.

It works on local Supabase but not on the hosted project

The Supabase CLI catches local email in its own mail viewer (usually at localhost:54324) and reads templates from supabase/config.toml. The hosted project uses the dashboard’s templates, sender and rate limits. Test on a hosted staging project before launch, with real email to an address that receives it.

Check them all in one pass

  1. Create a fresh Proxy Mail QA address for each scenario: new user, existing user, password reset, magic link.
  2. Go through the flow in your app. The code or link appears on the address’s row within seconds.
  3. Look at the row: a link to localhost is flagged, and the inbox shows whether the email says when its link expires.
  4. Open the link in the same browser you signed up in, and check you’re signed in on the right site.

Built with Lovable, Bolt or v0? Problems in vibe-coded sign-up and login covers what those apps usually get wrong on top of these.

Try it on your next sign-up test

Free plan, no credit card. Create an address and watch the code or link arrive.

Create a free accountOpen the app

Questions

Sign-up succeeded but no confirmation email came. Why?

Three usual reasons: the address already has a confirmed account, so Supabase answers as if it worked and sends nothing; Confirm email is switched off, so the user is signed in straight away; or the built-in sender refused it, because it only emails your project’s team. Sign up with a fresh address each time, and set up custom SMTP.

Why do I see "For security purposes, you can only request this after 60 seconds"?

Supabase allows one confirmation, magic-link, code or reset email per user every 60 seconds by default. Wait a minute, or use a new address for the next test. The window is under Authentication, Rate Limits.

The link works on my computer but not my client’s. Why?

Either their email service opened the link first to scan it, which uses up a one-time link, or they opened it in a different browser from the one they signed up in, which a PKCE link can’t finish. A 6-digit code avoids both.

How long do Supabase links and codes last?

One hour by default, and each works once. Change it under Authentication, Sign In / Providers, Email, Email OTP expiration. Asking for another email replaces the previous link.

Built your app with an AI tool? Pick yours

Supabase is a trademark of Supabase, Inc. Proxy Mail QA is independent and isn’t affiliated with or endorsed by them.