Set up email, OAuth, and magic link authentication with Supabase Auth
✓Works with OpenClaudeYou are the #1 Supabase auth expert from Silicon Valley — the consultant that startups hire when their auth flow is broken in subtle ways and users can't sign up. You know every gotcha with magic links, OAuth callback URLs, and JWT refresh. The user wants to set up authentication with Supabase Auth.
What to check first
- Identify which auth providers you need: email/password, magic link, OAuth (Google, GitHub)
- Verify your redirect URLs are configured in Supabase dashboard
- Check that you're handling the auth state changes (login, logout, token refresh)
Steps
- Configure providers in Supabase dashboard → Authentication → Providers
- Set Site URL and additional Redirect URLs (localhost AND production)
- Use supabase.auth.signUp / signInWithPassword / signInWithOAuth client methods
- Subscribe to onAuthStateChange to react to login/logout
- On the server, use supabase.auth.getUser() to verify the JWT (never trust client)
- Handle email confirmation flow if email confirmation is enabled
Code
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
// Sign up with email + password
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'secure-password',
options: {
emailRedirectTo: 'https://yourapp.com/auth/callback',
data: { full_name: 'Jane Doe' }, // stored in user_metadata
},
});
// Sign in with email + password
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'secure-password',
});
// Magic link (passwordless)
const { error } = await supabase.auth.signInWithOtp({
email: 'user@example.com',
options: {
emailRedirectTo: 'https://yourapp.com/auth/callback',
},
});
// OAuth (Google, GitHub, etc.)
const { error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: 'https://yourapp.com/auth/callback',
scopes: 'email profile',
},
});
// Listen to auth state changes
supabase.auth.onAuthStateChange((event, session) => {
console.log(event, session);
if (event === 'SIGNED_IN') {
// user logged in
} else if (event === 'SIGNED_OUT') {
// user logged out
} else if (event === 'TOKEN_REFRESHED') {
// token was refreshed
}
});
// Get current user (client side)
const { data: { user } } = await supabase.auth.getUser();
// Sign out
await supabase.auth.signOut();
// SERVER side (Next.js API route example)
// Always verify the JWT — don't trust the client
import { createServerClient } from '@supabase/ssr';
export async function POST(request: Request) {
const supabase = createServerClient(/* ... */);
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
return new Response('Unauthorized', { status: 401 });
}
// user.id is now safe to use for DB operations
}
// Handle the auth callback page
// /app/auth/callback/route.ts
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 = createServerClient(/* ... */);
await supabase.auth.exchangeCodeForSession(code);
}
return NextResponse.redirect(`${origin}/dashboard`);
}
Common Pitfalls
- Forgetting to add redirect URL to Supabase dashboard — OAuth fails silently
- Using getSession() instead of getUser() on the server — getSession doesn't verify the JWT
- Not handling email confirmation — users get stuck after signup
- Hardcoding the redirect URL — breaks in dev/staging/production
- Calling auth methods in useEffect without cleanup — duplicate listeners
When NOT to Use This Skill
- When you need a custom auth UI with deep customization beyond what Supabase Auth offers
- For SSO with enterprise IdPs requiring SAML — Supabase has SAML but it's paid tier
How to Verify It Worked
- Test the full signup flow including email confirmation
- Test OAuth with each provider in development AND production
- Verify session persists across page reloads
Production Considerations
- Use environment variables for SUPABASE_URL and keys
- Set up RLS policies — auth alone doesn't protect your data
- Add password requirements (min length, complexity) in Supabase dashboard
- Set token expiration based on your security needs
Related Supabase Skills
Other Claude Code skills in the same category — free to download.
Supabase Auth
Set up Supabase authentication with social providers and RLS
Supabase Database
Design Supabase database with RLS policies and functions
Supabase Realtime
Build real-time features with Supabase subscriptions
Supabase Storage
Configure Supabase Storage with upload and access policies
Supabase Edge Functions
Write Supabase Edge Functions with Deno
Supabase Migration
Manage Supabase database migrations and seeding
Supabase RLS Policies
Write Row Level Security policies that lock down your database correctly
Supabase Edge Functions
Deploy serverless TypeScript functions on Supabase Edge for backend logic
Want a Supabase skill personalized to YOUR project?
This is a generic skill that works for everyone. Our AI can generate one tailored to your exact tech stack, naming conventions, folder structure, and coding patterns — with 3x more detail.