// Authentication and access control skill for Next.js 15 + Supabase applications. Use when implementing user authentication, protecting routes, managing user sessions, enforcing role-based access control (admin/member), or working with multi-tenant family-based data isolation. Covers login/logout, registration with email verification, OAuth (GitHub), route protection for Server Components and Server Actions, admin-only features, and multi-tenant data access patterns.
| name | auth |
| description | Authentication and access control skill for Next.js 15 + Supabase applications. Use when implementing user authentication, protecting routes, managing user sessions, enforcing role-based access control (admin/member), or working with multi-tenant family-based data isolation. Covers login/logout, registration with email verification, OAuth (GitHub), route protection for Server Components and Server Actions, admin-only features, and multi-tenant data access patterns. |
This skill provides workflows for implementing authentication and access control in this Next.js 15 + Supabase application using server-side auth with httpOnly cookies, hybrid route protection, and multi-tenant family-based data isolation.
To protect a route from unauthenticated users:
requireAuthRedirect from @/lib/auth/server-authawait requireAuthRedirect() at the start of the component/login if not authenticatedimport { requireAuthRedirect } from '@/lib/auth/server-auth';
export default async function ProtectedPage() {
await requireAuthRedirect();
// User guaranteed authenticated here
return <YourContent />;
}
To protect an entire route group, add this to the layout component. All child routes will inherit the protection.
To require authentication in a Server Action:
requireAuth from @/lib/auth/server-authconst user = await requireAuth() at the start of the actionUnauthorizedError if user not authenticated'use server';
import { requireAuth } from '@/lib/auth/server-auth';
export async function myAction() {
const user = await requireAuth();
// Proceed with authenticated action
}
getCurrentUser() - Auth user (email, id), returns null if not logged ingetUserData() - Extended profile (role, familyId, firstName, lastName, active)getCurrentFamilyId() - Just the family IDAll use React cache() - multiple calls in same request return cached value.
To restrict a page to admins:
import { requireAdminRedirect } from '@/lib/auth/server-auth';
export default async function AdminPage() {
await requireAdminRedirect();
// User guaranteed to be admin
return <AdminPanel />;
}
To restrict a Server Action to admins:
'use server';
import { requireAdmin } from '@/lib/auth/server-auth';
export async function adminAction() {
await requireAdmin(); // Throws if not admin
// Proceed
}
To conditionally show admin UI:
import { isAdmin } from '@/lib/auth/server-auth';
export default async function Page() {
const userIsAdmin = await isAdmin();
return (
<>
<RegularContent />
{userIsAdmin && <AdminControls />}
</>
);
}
To ensure users only access their own family's data:
'use server';
import { requireFamilyAccess } from '@/lib/auth/server-auth';
export async function updateFamilyData(familyId: string, data: any) {
await requireFamilyAccess(familyId); // Throws if user not in this family
// User guaranteed to belong to this family
await updateDatabase(familyId, data);
}
When fetching current user's family data, use getCurrentFamilyId() instead - no need for requireFamilyAccess since it's their own family.
To create a new auth page (login, register, password reset):
src/app/(auth)/page-name/(auth) group layout automatically redirects authenticated users to /dashboardactions.ts fileconst supabase = await createClient()Pages in (auth) group are automatically protected from authenticated users - they'll be redirected to dashboard if already logged in.
Use supabase.auth.signInWithPassword() for login and supabase.auth.signOut() for logout. See references/patterns.md for complete code examples.
supabase.auth.signInWithOAuth({ provider: 'github', options: {...} })src/app/auth/callback/route.tsSee references/patterns.md for full implementation examples.
supabase.auth.getUser() to validate tokens (revalidates with server)supabase.auth.getSession() in server code (can be spoofed)src/lib/auth/server-auth.ts are server-side only'use server' directive to server-auth.ts (breaks class exports)updateSession() from src/lib/supabase/middleware.tsgetUser() to revalidate tokensFor detailed information, see:
references/file-tree.md - Complete file structure and organizationreferences/security.md - Security best practices and requirementsreferences/patterns.md - Code examples and common patternsreferences/flows.md - Authentication flow diagramsKey Files: src/lib/auth/server-auth.ts (helpers), src/middleware.ts (token refresh), src/app/dashboard/layout.tsx (dashboard protection)
Environment: NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY, NEXT_PUBLIC_SITE_URL
Database: auth.users (Supabase auth), public.families (households), public.users (profiles)
'use server' export error: Remove 'use server' from server-auth.ts - these are utilities, not actions
Middleware redirect fails: Use requireAuth() in Server Actions - middleware redirects don't work with POST
Multi-tenant access denied: Use requireFamilyAccess(familyId) to validate family ownership