supabase-auth
Apply when implementing authentication: sign up, sign in, OAuth providers, session management, and protected routes.
When & Why to Use This Skill
This Claude skill provides a comprehensive toolkit for implementing secure authentication using Supabase. It streamlines the integration of essential identity features including email/password sign-ups, OAuth social logins, and robust session management. By focusing on modern security standards like @supabase/ssr and server-side verification, it helps developers build production-ready authentication flows while avoiding common pitfalls in Next.js and React environments.
Use Cases
- Case 1: Implementing secure Email and Password authentication with custom user metadata and sign-up/sign-in flows.
- Case 2: Integrating third-party social providers like Google or GitHub using OAuth for a seamless user onboarding experience.
- Case 3: Securing application routes in Next.js using middleware and the recommended getUser() pattern to prevent unauthorized access.
- Case 4: Managing real-time authentication states with custom React hooks to handle session persistence and UI updates.
- Case 5: Setting up automated password reset workflows and secure user profile management.
| name | supabase-auth |
|---|---|
| description | Apply when implementing authentication: sign up, sign in, OAuth providers, session management, and protected routes. |
| version | 1.1.0 |
| tokens | ~750 |
| confidence | high |
| - https | //supabase.com/docs/guides/auth/server-side/nextjs |
| last_validated | 2025-12-10 |
| next_review | 2025-12-24 |
| tags | [supabase, auth, authentication, security] |
When to Use
Apply when implementing authentication: sign up, sign in, OAuth providers, session management, and protected routes.
Patterns
Pattern 1: Email/Password Auth
// Source: https://supabase.com/docs/reference/javascript/auth-signinwithpassword
// Sign up
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'securepassword',
options: {
data: { full_name: 'John Doe' }, // Custom user metadata
},
});
// Sign in
const { data, error } = await supabase.auth.signInWithPassword({
email: 'user@example.com',
password: 'securepassword',
});
// Sign out
await supabase.auth.signOut();
Pattern 2: OAuth Provider
// Source: https://supabase.com/docs/guides/auth/social-login
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google', // or 'github', 'discord', etc.
options: {
redirectTo: `${window.location.origin}/auth/callback`,
},
});
// In /auth/callback/route.ts (Next.js)
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const code = searchParams.get('code');
if (code) {
const supabase = createServerClient();
await supabase.auth.exchangeCodeForSession(code);
}
return NextResponse.redirect(new URL('/', request.url));
}
Pattern 3: Auth State Hook
// Source: https://supabase.com/docs/guides/auth
import { useEffect, useState } from 'react';
import { User } from '@supabase/supabase-js';
export function useAuth() {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Get initial session
supabase.auth.getSession().then(({ data: { session } }) => {
setUser(session?.user ?? null);
setLoading(false);
});
// Listen for changes
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_event, session) => setUser(session?.user ?? null)
);
return () => subscription.unsubscribe();
}, []);
return { user, loading };
}
Pattern 4: Protected Route (Next.js Middleware) - @supabase/ssr
// Source: https://supabase.com/docs/guides/auth/server-side/nextjs
// IMPORTANT: Use @supabase/ssr, NOT deprecated @supabase/auth-helpers-nextjs
// middleware.ts
import { createServerClient } from '@supabase/ssr';
import { NextResponse, type NextRequest } from 'next/server';
export async function middleware(request: NextRequest) {
let response = NextResponse.next({ request });
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
request.cookies.set(name, value)
);
response = NextResponse.next({ request });
cookiesToSet.forEach(({ name, value, options }) =>
response.cookies.set(name, value, options)
);
},
},
}
);
// CRITICAL: Use getUser() (not getSession()) in middleware for security
const { data: { user } } = await supabase.auth.getUser();
if (!user && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return response;
}
export const config = { matcher: ['/dashboard/:path*'] };
Pattern 5: Password Reset
// Source: https://supabase.com/docs/reference/javascript/auth-resetpasswordforemail
// Request reset
await supabase.auth.resetPasswordForEmail(email, {
redirectTo: `${origin}/auth/reset-password`,
});
// Update password (after clicking email link)
await supabase.auth.updateUser({ password: newPassword });
Anti-Patterns
- Using deprecated @supabase/auth-helpers-nextjs - Migrate to @supabase/ssr
- Using getSession() in middleware - Use getUser() for security
- Storing password in state - Clear after auth call
- No loading state - Show spinner during auth checks
- Ignoring errors - Always handle and display auth errors
Verification Checklist
- Using @supabase/ssr (NOT auth-helpers-nextjs)
- Middleware uses getUser() (NOT getSession())
- onAuthStateChange listener with cleanup
- OAuth callback route configured
- Error messages shown to user
- Loading states during auth operations