Skip to main content
RapidDev - Software Development Agency
App Featuresauth-security17 min read

How to Add User Auth and Registration to Your App (Copy-Paste Prompts Included)

User auth needs three layers: an auth provider (Supabase Auth handles sign-up, JWT issuance, and email verification for free), protected routes that redirect unauthenticated visitors, and a profiles table with RLS so users only read their own data. With Lovable you can have email + Google login working in 1–2 hours for $0/month up to 50,000 monthly active users.

4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members

Feature spec

Beginner

Category

auth-security

Build with AI

1–3 hours with Lovable or FlutterFlow

Custom build

3–5 days custom dev

Running cost

$0/mo up to 50K MAU; $25/mo Supabase Pro for production reliability

Works on

WebMobile

Everything it takes to ship User Authentication and Registration — parts, prompts, and real costs.

TL;DR

User auth needs three layers: an auth provider (Supabase Auth handles sign-up, JWT issuance, and email verification for free), protected routes that redirect unauthenticated visitors, and a profiles table with RLS so users only read their own data. With Lovable you can have email + Google login working in 1–2 hours for $0/month up to 50,000 monthly active users.

What User Authentication and Registration Actually Is

Authentication answers the question 'who are you?' and registration is the moment a new user first answers it. Together they cover sign-up with email and password, email verification so you know addresses are real, social OAuth so users don't have to remember yet another password, session management so login persists across page refreshes, and password reset when they forget. Supabase Auth handles all of this behind a clean JavaScript SDK — you never store a raw password or roll your own JWT logic. The real product decisions are which OAuth providers to support, whether email verification is required at signup, and what a user can see before their first login.

What users consider table stakes in 2026

  • Email and password sign-up with confirmation that a verification email was sent
  • Social OAuth buttons (Google at minimum) that open a provider redirect — not a popup inside a preview iframe
  • Persistent sessions that survive page refresh and browser close (Supabase Auth uses refresh token rotation by default)
  • Password reset via email link that lands the user on a reset page, not the homepage
  • Clear inline error messages: 'Email already registered', 'Password must be 8+ characters', 'Invalid credentials'
  • Profile management page showing the user's email and display name after first login

Anatomy of the Feature

Six components work together. Supabase Auth handles the hard parts (hashing, JWT, refresh) — your job is to wire the UI and protect the routes.

Layers:UIDataBackend

Auth provider — Supabase Auth

Backend

Handles sign-up, sign-in, JWT issuance and rotation, session refresh, email verification, and password reset. Replaces building bcrypt hashing, session tables, and token rotation from scratch. Configured in Supabase Dashboard under Authentication → Providers and Settings.

Note: Supabase Auth includes 50,000 MAU on the free tier. For Lovable Cloud projects, Supabase is provisioned automatically but is not visible in the Supabase Dashboard — manage it via Lovable's Cloud tab.

Sign-up and login forms

UI

React forms using shadcn/ui Form, react-hook-form, and zod for validation. Sign-up: email, password, confirm-password fields with inline error messages. Login: email, password, and a 'Forgot password?' link. Submission calls supabase.auth.signUp() or supabase.auth.signInWithPassword().

Note: Zod schema enforces password minimum length and matching confirm-password client-side before any network call — reduces unnecessary API round-trips.

OAuth buttons

UI

Single button per provider that calls supabase.auth.signInWithOAuth({ provider: 'google', options: { redirectTo: window.location.origin + '/auth/callback' } }). Opens the provider's login page in a full redirect — never inside an iframe.

Note: The redirectTo URL must be registered in Supabase Dashboard → Authentication → Redirect URLs. Update this when you publish to a custom domain.

Auth state listener

Backend

supabase.auth.onAuthStateChange() fires on every sign-in, sign-out, and token refresh. Used to update a React auth context that all components read, trigger profile creation on SIGNED_IN with no existing profile, and redirect users after OAuth callback.

Note: This is the correct place to drive protected route logic — not a one-time check on component mount.

Protected route guard

UI

A React component (or Next.js middleware) that reads the current session from auth context and either renders children or redirects to /login. In Next.js App Router, a middleware.ts file at the root intercepts unauthenticated requests to /dashboard/* before any page renders.

Note: In Lovable (React Router), wrap protected routes in an AuthGuard component that checks session and redirects. In Next.js (V0), use middleware.ts with supabase.auth.getSession() from @supabase/ssr.

Profiles table with RLS

Data

Supabase auto-populates auth.users on sign-up but it is not directly queryable by the client. A public.profiles table mirrors it with user-facing fields: display_name, avatar_url, created_at. An INSERT policy triggered by auth state or an Auth hook creates the profile row on first sign-in.

Note: Without RLS, any authenticated user can read any other user's profile. Add a SELECT policy scoped to auth.uid() = id immediately after table creation.

The data model

One profiles table is all most apps need. Run this in the Supabase SQL editor (Dashboard → SQL Editor → New Query):

schema.sql
1create table public.profiles (
2 id uuid primary key references auth.users(id) on delete cascade,
3 display_name text,
4 avatar_url text,
5 created_at timestamptz not null default now(),
6 updated_at timestamptz not null default now()
7);
8
9alter table public.profiles enable row level security;
10
11create policy "Users can view own profile"
12 on public.profiles for select
13 using (auth.uid() = id);
14
15create policy "Users can update own profile"
16 on public.profiles for update
17 using (auth.uid() = id);
18
19create policy "Users can insert own profile"
20 on public.profiles for insert
21 with check (auth.uid() = id);
22
23-- Auto-create profile row when a new user signs up
24create or replace function public.handle_new_user()
25returns trigger as $$
26begin
27 insert into public.profiles (id, display_name, avatar_url)
28 values (
29 new.id,
30 new.raw_user_meta_data->>'full_name',
31 new.raw_user_meta_data->>'avatar_url'
32 );
33 return new;
34end;
35$$ language plpgsql security definer;
36
37create trigger on_auth_user_created
38 after insert on auth.users
39 for each row execute procedure public.handle_new_user();

Heads up: The trigger auto-populates display_name and avatar_url from OAuth metadata (Google, GitHub) so the profile is filled in on first social login without any extra code.

Build it — pick your path

Each tool fits this feature differently. Switch tabs to compare fit, time, the exact steps, and a copy-paste prompt.

Full-stack, non-technical friendlyFit for this feature:

Best first choice for non-technical founders: Lovable generates full Supabase Auth integration — email sign-up, Google OAuth, protected routes, and profiles table — from a single detailed prompt. Auto-creates the Edge Functions and RLS policies.

Step by step

  1. 1Create a new Lovable project and connect Lovable Cloud (Cloud tab → Database) so Supabase is provisioned automatically
  2. 2Paste the prompt below in Agent Mode and let Lovable build the auth pages, callback handler, and protected dashboard route
  3. 3Open Cloud tab → Secrets and verify VITE_SUPABASE_URL and VITE_SUPABASE_PUBLISHABLE_KEY are present
  4. 4Click Publish (top-right icon) to get a real HTTPS URL — OAuth and email verification only work on the published URL, not the preview
  5. 5In Lovable Cloud tab → Database, go to Auth → Redirect URLs and add your published URL (e.g., https://yourapp.lovable.app)
Paste into Lovable
Build a complete user authentication system using Supabase Auth. Pages needed: 1) /register — sign-up form with email, password (min 8 chars), confirm-password fields; inline zod validation showing errors under each field; on submit call supabase.auth.signUp() and redirect to /verify-email. 2) /verify-email — static page saying 'Check your inbox and click the link to continue'; include a 'Resend email' button. 3) /login — email and password fields with a 'Forgot password?' link that calls supabase.auth.resetPasswordForEmail(); Google OAuth button that calls signInWithOAuth({ provider: 'google' }) using a full redirect (not popup); error message if credentials are wrong. 4) /auth/callback — page that calls supabase.auth.exchangeCodeForSession() from the URL, then redirects to /dashboard. 5) /dashboard — protected route that redirects unauthenticated users to /login; shows 'Welcome, {display_name}' from the profiles table. 6) /profile — shows user email and display_name from profiles table with an edit form. Create a profiles table (id uuid references auth.users, display_name text, avatar_url text, created_at timestamptz) with RLS: users can only SELECT and UPDATE their own row. Use a Supabase database trigger on auth.users INSERT to auto-create the profile row. Loading state while session check runs on first page load. Google OAuth button should work on the published URL after redirect URL is configured.

Where this path bites

  • Google OAuth callback fails in the Lovable preview iframe — always test on the published URL
  • Lovable Cloud Supabase instance is not visible in the Supabase Dashboard; manage auth settings from the Cloud tab
  • Iterating heavily on auth UI design burns credits quickly — finalize the design before prompting auth logic

Third-party services you'll need

Supabase Auth is the core dependency. Email delivery and OAuth provider credentials are the only external services to configure:

ServiceWhat it doesFree tierPaid from
Supabase AuthSign-up, sign-in, JWT issuance, session refresh, email verification, password reset50,000 MAU free; 3 emails/hour on free SMTP$25/mo Pro (100,000 MAU; higher email volume)
Google OAuthSign in with Google button; provides name and avatar on first loginFree — requires Google Cloud Console OAuth 2.0 credentialsFree (no per-sign-in charge)
ResendEmail delivery for verification and password reset emails (replaces Supabase's 3/hour limit in production)3,000 emails/month free$20/mo for higher volume

Swipe the table sideways to see pricing.

What it costs to run

Drag through the tiers to see how your monthly bill scales with users — no surprises later.

Estimated monthly running cost

$0/mo

Supabase free tier covers well below 50K MAU. Resend free tier handles verification and reset emails. Google OAuth has no per-sign-in cost.

Estimates use verified 2026 pricing and assume typical usage per user. Your real bill depends on activity, storage, and third-party plans.

What breaks when AI tools build this

The failures people actually hit on their first build — the symptom, why it happens, and the exact fix.

Google OAuth fails silently in the Lovable preview iframe

Symptom: supabase.auth.signInWithOAuth() opens a redirect to accounts.google.com. The Lovable preview panel is an iframe with a sandboxed origin — Google's OAuth server blocks callbacks to non-registered URLs, so the redirect either fails with a blank page or throws a redirect_uri_mismatch error with no visible message in the preview.

Fix: Test Google OAuth only on the published Lovable URL. Click Publish (top-right icon), open the live URL in a real browser tab, and add that URL to Supabase Dashboard → Authentication → Redirect URLs before testing.

RLS blocks all data after auth is wired up

Symptom: AI tools generate the auth flow and often create the profiles table, but frequently skip adding RLS policies. Without a SELECT policy, supabase.from('profiles').select() returns an empty array even for the logged-in user — not an error, just silence. This makes it look like the profile was never created.

Fix: After Lovable or V0 generates the schema, open Supabase Dashboard → Table Editor → profiles → RLS and verify there is a SELECT policy with USING (auth.uid() = id). If missing, add it manually or prompt: 'Add an RLS SELECT policy on profiles that allows users to read only their own row.'

Email not confirmed error loops at login

Symptom: Supabase requires email verification by default. AI-generated apps sometimes skip building the /verify-email page and the re-send logic, leaving new users stranded after sign-up with no clear next step. They try to log in, get 'Email not confirmed', and have no way to resend the email.

Fix: Add a /verify-email page that shows a 'Check your inbox' message and a 'Resend verification email' button calling supabase.auth.resend(). During development, disable email confirmation in Supabase Dashboard → Authentication → Settings → 'Enable email confirmations' (re-enable before launch).

Session lost on page refresh in V0 Next.js apps

Symptom: V0 sometimes generates session reads using localStorage or supabase.auth.getSession() inside a useEffect that runs only after hydration. During SSR, the server renders the page as if no user is logged in, sends it to the browser, then the client re-checks — causing a flash of the login screen for authenticated users.

Fix: Use @supabase/ssr createServerClient in Server Components and route handlers to read the session from cookies, not localStorage. Never access the Supabase auth session from a Server Component using createBrowserClient.

Duplicate auth.users records from interrupted OAuth

Symptom: If a user starts a Google OAuth flow and closes the browser tab before the callback completes, Supabase may create a partial auth.users record. Re-attempting sign-in with the same Google account sometimes creates a second record because the first didn't complete the email verification handshake.

Fix: Add an onAuthStateChange listener that checks for an existing profile row before treating a SIGNED_IN event as a new user. Supabase Auth deduplicates by email when the same OAuth provider is used — the real risk is a user who also registered with email/password first, creating two accounts for the same email.

Best practices

1

Always protect routes at the middleware level (Next.js) or with an AuthGuard component (React Router) — never rely only on hiding UI elements

2

Store JWTs in httpOnly cookies via @supabase/ssr rather than localStorage to prevent XSS token theft

3

Require email verification before granting access to the main app, but make the verification step clear and include a resend button

4

Write RLS policies on every table that contains user data — auth alone is not enough if the Supabase REST API is accessible

5

Use the Supabase Auth trigger pattern to auto-create profile rows on sign-up, so profile reads never return null for real users

6

Set redirect URLs to exact production domains in both Supabase Dashboard and each OAuth provider's console — wildcard redirects are a security risk

7

Add a loading state while the initial session check runs to prevent flashing the login screen to authenticated users on page load

8

Customize email templates in Supabase Dashboard → Authentication → Email Templates before launch — the default 'Supabase' branding erodes trust

When You Need Custom Development

Supabase Auth with Lovable or V0 covers the vast majority of app authentication needs. Custom development becomes necessary when:

  • You need SAML/SSO for enterprise clients who require login through their own identity provider (Okta, Azure AD, Google Workspace)
  • You need custom session expiry policies beyond Supabase's defaults — for example, 8-hour sessions for internal tools or 90-day 'remember me' for consumer apps
  • You have GDPR right-to-erasure requirements that demand a deletion workflow cascading through all user-linked tables with an audit trail
  • You need sign-in audit logs recording every authentication event per user for compliance or security monitoring

RapidDev builds these features for production

Real auth, database, and payments — fixed price, delivered in weeks. You own 100% of the code.

Get a fixed-price quote

Frequently asked questions

Is Supabase Auth free for small apps?

Yes. Supabase Auth is free up to 50,000 monthly active users on the free tier. For most early-stage apps this covers everything indefinitely. The Supabase Pro plan ($25/mo) adds higher MAU limits, better email delivery rates, and production SLA — worth it once you have paying users.

How do I add Google login to my Lovable app?

Three steps: 1) Go to Google Cloud Console, create an OAuth 2.0 credential, and copy the Client ID and Secret. 2) In Supabase Dashboard → Authentication → Providers, enable Google and paste the credentials. 3) Add your published Lovable URL to Supabase Dashboard → Authentication → Redirect URLs. Then prompt Lovable to add a Google OAuth button. Test on the published URL — OAuth does not work in the preview iframe.

What's the difference between authentication and authorization?

Authentication is proving who you are (logging in). Authorization is deciding what you're allowed to do once logged in. Your sign-up and login system handles authentication. Row Level Security policies and custom roles handle authorization — they determine whether the logged-in user can read a specific row in a specific table.

Do I need email verification for my MVP?

It depends on your risk tolerance. Without verification, users can register with fake or typo'd emails — you lose the ability to contact them and your email reputation suffers if you later send to bad addresses. For a private beta or internal tool, disabling it speeds up testing. For any app collecting user data or sending transactional emails, enable it before launch.

How do I protect pages so only logged-in users can see them?

In Next.js (V0), add a middleware.ts file that checks the Supabase session on every request to /dashboard/* and redirects to /login if none exists. In Lovable (React Router), create an AuthGuard component that reads the session from auth context and returns a redirect element if the session is null. Both checks should happen before any protected page content renders.

Can I use both email and Google login at the same time?

Yes, and Supabase Auth handles the account linking automatically. If a user registers with email/password and then tries to sign in with Google using the same email, Supabase links both providers to the same auth.users record. You can see the linked identities in user.identities[] in the session object.

What happens to user data if I delete an account?

Deleting a row from auth.users does not automatically delete data in your public tables unless you set up ON DELETE CASCADE on the foreign key references. The profiles table schema above includes ON DELETE CASCADE — but any other tables (posts, orders, files) need it too. For GDPR compliance, use a Supabase Edge Function with the service role key to cascade-delete across all tables in a single transaction.

How do I customize the verification email template?

Go to Supabase Dashboard → Authentication → Email Templates. You can edit the subject line, HTML body, and the confirmation link placeholder. Add your logo, brand colors, and a clear call to action. Custom SMTP (via Resend) removes the 3 emails/hour free tier limit and lets you send from your own domain, which improves deliverability significantly.

RapidDev

Need this feature production-ready?

RapidDev builds user authentication and registration into real apps — auth, database, payments — at $13K–$25K.

Book a free consultation

30-min call. No commitment.

Want this built for you?

We ship production apps at a fixed price — $13K–$25K, 6–10 weeks, source code yours. You've seen what it takes; we do it every week.

Get a fixed-price quote

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.