Supabase Auth: Social Login and Row Level Security in 30 Minutes
Supabase Auth handles OAuth providers, magic links, and phone auth — all tied directly to PostgreSQL Row Level Security policies so your database enforces access control automatically.
Install
npm install @supabase/supabase-js @supabase/ssr
Client Setup
// 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!
);
}
Google OAuth Login
const supabase = createClient();
async function signInWithGoogle() {
const { error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: `${window.location.origin}/auth/callback`,
},
});
if (error) console.error(error);
}
Auth Callback Route
// app/auth/callback/route.ts
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';
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 cookieStore = cookies();
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{ cookies: { getAll: () => cookieStore.getAll(), setAll: (cs) => cs.forEach(c => cookieStore.set(c)) } }
);
await supabase.auth.exchangeCodeForSession(code);
}
return NextResponse.redirect(`${origin}/dashboard`);
}
Row Level Security
-- Enable RLS on your table
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- Users can only read their own posts
CREATE POLICY "Users see own posts" ON posts
FOR SELECT USING (auth.uid() = user_id);
-- Users can only insert posts with their own user_id
CREATE POLICY "Users create own posts" ON posts
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- Public posts visible to everyone
CREATE POLICY "Public posts visible" ON posts
FOR SELECT USING (published = true);
Querying with RLS Enforced
// RLS automatically filters — user only sees their own posts
const { data: posts } = await supabase
.from('posts')
.select('*');
// No WHERE clause needed — RLS handles it
// Insert respects RLS too
const { error } = await supabase
.from('posts')
.insert({ title: 'My Post', user_id: user.id });
// Fails if user_id doesn't match auth.uid()
Server-Side Session
// In Server Components
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';
async function getUser() {
const supabase = createServerClient(url, key, { cookies: { getAll: () => cookies().getAll() } });
const { data: { user } } = await supabase.auth.getUser();
return user;
}
Full Supabase integration (Auth + RLS + Realtime) is an option in the AI SaaS Starter Kit. $99 at whoffagents.com.
Top comments (0)