Agent Skills: supabase-auth

>

UncategorizedID: poletron/custom-rules/supabase-auth

Install this agent skill to your local

pnpm dlx add-skill https://github.com/odjaramillo/custom-rules/tree/HEAD/registry/skills/supabase-auth

Skill Files

Browse the full folder contents for supabase-auth.

Download Skill

Loading file tree…

registry/skills/supabase-auth/SKILL.md

Skill Metadata

Name
supabase-auth
Description
>

🚨 CRITICAL: DEPRECATED PATTERNS 🚨

NEVER generate these patterns - they BREAK the application:

// ❌ NEVER USE - BREAKS APPLICATION
{
  cookies: {
    get(name: string) {                 // ❌ BREAKS
      return cookieStore.get(name)
    },
    set(name: string, value: string) {  // ❌ BREAKS
      cookieStore.set(name, value)
    },
    remove(name: string) {              // ❌ BREAKS
      cookieStore.remove(name)
    }
  }
}

// ❌ NEVER import from auth-helpers-nextjs - DEPRECATED
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'  // ❌
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'  // ❌

Critical Patterns

ALWAYS Use This Pattern (REQUIRED)

// βœ… CORRECT - Only use getAll and setAll
{
  cookies: {
    getAll() {
      return cookieStore.getAll()
    },
    setAll(cookiesToSet) {
      cookiesToSet.forEach(({ name, value, options }) =>
        cookieStore.set(name, value, options)
      )
    }
  }
}

Browser Client (REQUIRED)

import { createBrowserClient } from '@supabase/ssr';

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

Server Client (REQUIRED)

import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';

export async function createClient() {
  const cookieStore = await cookies();

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll();
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) =>
              cookieStore.set(name, value, options),
            );
          } catch {
            // Called from Server Component - ignored if middleware refreshes sessions
          }
        },
      },
    },
  );
}

Middleware (REQUIRED)

import { createServerClient } from '@supabase/ssr';
import { NextResponse, type NextRequest } from 'next/server';

export async function middleware(request: NextRequest) {
  let supabaseResponse = 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 }) => request.cookies.set(name, value));
          supabaseResponse = NextResponse.next({ request });
          cookiesToSet.forEach(({ name, value, options }) =>
            supabaseResponse.cookies.set(name, value, options),
          );
        },
      },
    },
  );

  // IMPORTANT: DO NOT REMOVE auth.getUser()
  const {
    data: { user },
  } = await supabase.auth.getUser();

  if (
    !user &&
    !request.nextUrl.pathname.startsWith('/login') &&
    !request.nextUrl.pathname.startsWith('/auth')
  ) {
    const url = request.nextUrl.clone();
    url.pathname = '/login';
    return NextResponse.redirect(url);
  }

  // MUST return supabaseResponse as-is to avoid session sync issues
  return supabaseResponse;
}

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)'],
};

Decision Tree

Need browser client?       β†’ Use createBrowserClient from @supabase/ssr
Need server client?        β†’ Use createServerClient with getAll/setAll
Need route protection?     β†’ Use middleware with auth.getUser()
Need OAuth?                β†’ Use signInWithOAuth
Need magic link?           β†’ Use signInWithOtp

Code Examples

Sign Up / Sign In

// Sign up
const { data, error } = await supabase.auth.signUp({
  email: 'user@example.com',
  password: 'secure-password',
});

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

// Sign out
await supabase.auth.signOut();

Session Management

// Get current session
const {
  data: { session },
} = await supabase.auth.getSession();

// Listen to auth changes
supabase.auth.onAuthStateChange((event, session) => {
  if (event === 'SIGNED_IN') {
    // Handle sign in
  }
});

AI Verification Checklist

Before generating code, VERIFY:

  1. βœ… Using ONLY getAll and setAll?
  2. βœ… Importing from @supabase/ssr?
  3. ❌ Any get, set, or remove? β†’ FIX
  4. ❌ Importing from auth-helpers-nextjs? β†’ FIX

Consequences of incorrect implementation:

  • Breaks in production
  • Fails to maintain session state
  • Causes authentication loops
  • Security vulnerabilities