DEV Community

Atlas Whoff
Atlas Whoff

Posted on

Supabase Auth: Social Login and Row Level Security in 30 Minutes

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
Enter fullscreen mode Exit fullscreen mode

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!
  );
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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`);
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

Full Supabase integration (Auth + RLS + Realtime) is an option in the AI SaaS Starter Kit. $99 at whoffagents.com.

Top comments (0)