This skill should be used when configuring Supabase Auth for server-side rendering with Next.js App Router, including secure cookie handling, middleware protection, route guards, authentication utilities, and logout flow. Apply when setting up SSR auth, adding protected routes, implementing middleware authentication, configuring secure sessions, or building login/logout flows with Supabase.
Configures Supabase authentication for Next.js App Router with server-side rendering, secure cookie sessions, and middleware protection. Use this when setting up SSR auth, protecting routes, or implementing login/logout flows with Supabase.
/plugin marketplace add hopeoverture/worldbuilding-app-skills/plugin install supabase-auth-ssr-setup@worldbuilding-app-skillsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
assets/auth-actions.tsassets/auth-callback-route.tsassets/auth-utils.tsassets/dashboard-page.tsxassets/login-page.tsxassets/middleware.tsassets/supabase-client.tsassets/supabase-middleware.tsassets/supabase-server.tsreferences/authentication-patterns.mdreferences/security-considerations.mdConfigure Supabase Authentication for Next.js App Router with server-side rendering (SSR), secure cookie-based sessions, middleware protection, and complete authentication flows.
Install Supabase SSR package for Next.js:
npm install @supabase/supabase-js @supabase/ssr
Create three client configurations for different contexts (browser, server, middleware):
File: lib/supabase/client.ts (Browser client)
Use the template from assets/supabase-client.ts. This client:
File: lib/supabase/server.ts (Server component client)
Use the template from assets/supabase-server.ts. This client:
File: lib/supabase/middleware.ts (Middleware client)
Use the template from assets/supabase-middleware.ts. This client:
Add Supabase credentials to .env.local:
NEXT_PUBLIC_SUPABASE_URL=your-project-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
Get these values from your Supabase project settings under API.
Security note: The anon key is safe to expose publicly. Real security comes from Row Level Security (RLS) policies in your database.
Create middleware.ts in project root using the template from assets/middleware.ts. This middleware:
Configure protected routes by adjusting the matcher pattern:
export const config = {
matcher: [
'/dashboard/:path*',
'/settings/:path*',
'/api/protected/:path*',
],
};
Create helper functions for common auth operations using templates from assets/auth-utils.ts:
Get current user server-side:
import { getCurrentUser } from '@/lib/auth/utils';
const user = await getCurrentUser();
Require authentication:
import { requireAuth } from '@/lib/auth/utils';
const user = await requireAuth(); // Throws error if not authenticated
Get session:
import { getSession } from '@/lib/auth/utils';
const session = await getSession();
These utilities simplify authentication checks in Server Components and Server Actions.
Create app/actions/auth.ts using the template from assets/auth-actions.ts. This provides:
Logout action:
Use in client components:
import { logout } from '@/app/actions/auth';
<button onClick={() => logout()}>
Sign Out
</button>
Create app/login/page.tsx using the template from assets/login-page.tsx. This page:
Customize the login page:
Create a protected dashboard page at app/dashboard/page.tsx using the template from assets/dashboard-page.tsx. This demonstrates:
requireAuth() to protect routesIf using OAuth providers, create app/auth/callback/route.ts using the template from assets/auth-callback-route.ts. This handler:
Configure OAuth in Supabase dashboard:
https://your-domain.com/auth/callback/loginsignOut()Use requireAuth() at the top of Server Components:
import { requireAuth } from '@/lib/auth/utils';
export default async function ProtectedPage() {
const user = await requireAuth();
return <div>Hello {user.email}</div>;
}
Use Next.js route groups with layout:
// app/(protected)/layout.tsx
import { requireAuth } from '@/lib/auth/utils';
export default async function ProtectedLayout({ children }) {
await requireAuth();
return <>{children}</>;
}
All routes in (protected) group are automatically protected.
Check if user is logged in without requiring it:
import { getCurrentUser } from '@/lib/auth/utils';
export default async function OptionalAuthPage() {
const user = await getCurrentUser();
return (
<div>
{user ? `Welcome ${user.email}` : 'Please log in'}
</div>
);
}
Protect Server Actions using requireAuth():
'use server';
import { requireAuth } from '@/lib/auth/utils';
import { createServerClient } from '@/lib/supabase/server';
export async function updateProfile(formData: FormData) {
const user = await requireAuth();
const supabase = createServerClient();
const { error } = await supabase
.from('profiles')
.update({ name: formData.get('name') })
.eq('id', user.id);
if (error) throw error;
}
Session not persisting: Verify cookies are being set. Check browser dev tools > Application > Cookies. Ensure domain matches.
Middleware redirect loop: Check matcher pattern doesn't include login page. Verify /login is accessible without auth.
OAuth redirect fails: Confirm callback URL matches exactly in Supabase dashboard. Check for trailing slashes.
TypeScript errors: Install types: npm install -D @types/node. Ensure supabase is typed correctly.
401 errors on protected routes: Session may be expired. Check Supabase dashboard > Authentication > Settings for session timeout.
No executable scripts needed for this skill.
authentication-patterns.md - Common auth patterns and best practices for Next.js + Supabasesecurity-considerations.md - Security best practices for session handling and cookie configurationsupabase-client.ts - Browser-side Supabase client configurationsupabase-server.ts - Server-side Supabase client for Server Componentssupabase-middleware.ts - Middleware Supabase client for session refreshmiddleware.ts - Next.js middleware for route protectionauth-utils.ts - Helper functions for authentication checksauth-actions.ts - Server Actions for logout and other auth operationslogin-page.tsx - Complete login page with email/password and OAuthdashboard-page.tsx - Example protected page using requireAuthauth-callback-route.ts - OAuth callback handler for provider authentication