Step-by-Step Guide
7 steps

How to Add Authentication to Your Supabase App

Supabase Auth provides email/password, OAuth, magic links, and phone auth out of the box. It integrates directly with Row Level Security so authenticated users automatically get scoped database access. This guide covers the complete auth setup.

Find security issues automatically before attackers do.

Follow These Steps

1

Configure auth providers in Supabase dashboard

Enable the authentication methods you want to offer.

Code Example
// Supabase Dashboard > Authentication > Providers
// Enable:
// - Email (with Confirm email ON)
// - Google OAuth
// - GitHub OAuth

// Configure redirect URLs:
// Site URL: https://yourdomain.com
// Redirect URLs: https://yourdomain.com/auth/callback
2

Install Supabase auth helpers

Add the framework-specific auth helpers.

Code Example
npm install @supabase/supabase-js @supabase/ssr
3

Create the Supabase client with auth support

Set up client and server Supabase clients with proper cookie handling.

Code Example
// lib/supabase/client.ts
import { createBrowserClient } from '@supabase/ssr'

export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  )
}

// lib/supabase/server.ts
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'

export async function createServerSupabase() {
  const cookieStore = await cookies()
  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    { cookies: { getAll() { return cookieStore.getAll() } } }
  )
}
4

Implement signup, login, and OAuth

Create authentication functions.

Code Example
// Sign up with email
const { data, error } = await supabase.auth.signUp({
  email: 'user@example.com',
  password: 'securepassword'
})

// Sign in with email
const { data, error } = await supabase.auth.signInWithPassword({
  email: 'user@example.com',
  password: 'securepassword'
})

// Sign in with Google
const { data, error } = await supabase.auth.signInWithOAuth({
  provider: 'google',
  options: { redirectTo: 'https://yourdomain.com/auth/callback' }
})
5

Create the auth callback route

Handle the OAuth callback to exchange the code for a session.

Code Example
// app/auth/callback/route.ts
import { createServerSupabase } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url)
  const code = searchParams.get('code')
  
  if (code) {
    const supabase = await createServerSupabase()
    const { error } = await supabase.auth.exchangeCodeForSession(code)
    if (!error) {
      return NextResponse.redirect(`${origin}/dashboard`)
    }
  }
  return NextResponse.redirect(`${origin}/login?error=auth_failed`)
}
6

Protect server-side routes

Check authentication in Server Components and API routes.

Code Example
// app/dashboard/page.tsx
import { createServerSupabase } from '@/lib/supabase/server'
import { redirect } from 'next/navigation'

export default async function Dashboard() {
  const supabase = await createServerSupabase()
  const { data: { user } } = await supabase.auth.getUser()
  if (!user) redirect('/login')
  
  // RLS automatically scopes this query to the user
  const { data: posts } = await supabase.from('posts').select('*')
  return <PostList posts={posts} />
}
7

Link auth to RLS policies

Write RLS policies that use auth.uid() to scope data access.

Code Example
CREATE POLICY "Users access own data" ON "posts"
  FOR ALL TO authenticated
  USING ((select auth.uid()) = user_id);

With RLS and auth properly configured, every database query automatically returns only the current user's data.

What You'll Achieve

Your Supabase app has email, OAuth, and magic link authentication with proper session handling, protected routes, and RLS integration. Users can only access their own data through the combination of auth and RLS.

Common Mistakes to Avoid

Mistake

Using getSession() instead of getUser() for auth verification

Fix

getSession() reads from cookies which can be tampered with. Always use getUser() for server-side auth verification as it validates the JWT with Supabase.

Mistake

Not creating the auth callback route

Fix

OAuth and magic link flows require a callback route to exchange the code for a session. Without it, auth flows will fail silently.

Mistake

Forgetting to add redirect URLs in Supabase dashboard

Fix

OAuth redirects will fail if the callback URL is not listed in Supabase dashboard > Authentication > URL Configuration.

Frequently Asked Questions

Does Supabase Auth work with RLS automatically?

Yes. When a user is authenticated, their JWT is sent with every request. RLS policies can reference auth.uid() to scope queries to the authenticated user automatically.

Should I use email/password or OAuth?

Offer both. OAuth is more convenient for users and avoids password management. Email/password is essential as a fallback and for users who prefer it.

How do I handle auth in Server Components vs Client Components?

Use createServerClient for Server Components (reads cookies from the request). Use createBrowserClient for Client Components (manages cookies in the browser).

Ready to Secure Your App?

VAS automatically scans your deployed app for the security issues covered in this guide. Get actionable results in minutes.

Start Security Scan