[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-c8a4b2a5-b8e8-4d71-a85c-28afa9a5ef78":3,"$fUBqETUDDbukbuyY6xAQRWDaXxa3xEBIZJ1wTo4si5kM":43},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":34},"c8a4b2a5-b8e8-4d71-a85c-28afa9a5ef78","nextjs-supabase-auth","Supabase Auth与Next.js App Router的专家级集成","cat_coding_frontend","mod_coding","sickn33,coding","---\nname: nextjs-supabase-auth\ndescription: Expert integration of Supabase Auth with Next.js App Router\nrisk: none\nsource: vibeship-spawner-skills (Apache 2.0)\ndate_added: 2026-02-27\n---\n\n# Next.js + Supabase Auth\n\nExpert integration of Supabase Auth with Next.js App Router\n\n## Capabilities\n\n- nextjs-auth\n- supabase-auth-nextjs\n- auth-middleware\n- auth-callback\n\n## Prerequisites\n\n- Required skills: nextjs-app-router, supabase-backend\n\n## Patterns\n\n### Supabase Client Setup\n\nCreate properly configured Supabase clients for different contexts\n\n**When to use**: Setting up auth in a Next.js project\n\n\u002F\u002F lib\u002Fsupabase\u002Fclient.ts (Browser client)\n'use client'\nimport { createBrowserClient } from '@supabase\u002Fssr'\n\nexport function createClient() {\n  return createBrowserClient(\n    process.env.NEXT_PUBLIC_SUPABASE_URL!,\n    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!\n  )\n}\n\n\u002F\u002F lib\u002Fsupabase\u002Fserver.ts (Server client)\nimport { createServerClient } from '@supabase\u002Fssr'\nimport { cookies } from 'next\u002Fheaders'\n\nexport async function createClient() {\n  const cookieStore = await cookies()\n  return createServerClient(\n    process.env.NEXT_PUBLIC_SUPABASE_URL!,\n    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,\n    {\n      cookies: {\n        getAll() {\n          return cookieStore.getAll()\n        },\n        setAll(cookiesToSet) {\n          cookiesToSet.forEach(({ name, value, options }) => {\n            cookieStore.set(name, value, options)\n          })\n        },\n      },\n    }\n  )\n}\n\n### Auth Middleware\n\nProtect routes and refresh sessions in middleware\n\n**When to use**: You need route protection or session refresh\n\n\u002F\u002F middleware.ts\nimport { createServerClient } from '@supabase\u002Fssr'\nimport { NextResponse, type NextRequest } from 'next\u002Fserver'\n\nexport async function middleware(request: NextRequest) {\n  let response = NextResponse.next({ request })\n\n  const supabase = createServerClient(\n    process.env.NEXT_PUBLIC_SUPABASE_URL!,\n    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,\n    {\n      cookies: {\n        getAll() {\n          return request.cookies.getAll()\n        },\n        setAll(cookiesToSet) {\n          cookiesToSet.forEach(({ name, value, options }) => {\n            response.cookies.set(name, value, options)\n          })\n        },\n      },\n    }\n  )\n\n  \u002F\u002F Refresh session if expired\n  const { data: { user } } = await supabase.auth.getUser()\n\n  \u002F\u002F Protect dashboard routes\n  if (request.nextUrl.pathname.startsWith('\u002Fdashboard') && !user) {\n    return NextResponse.redirect(new URL('\u002Flogin', request.url))\n  }\n\n  return response\n}\n\nexport const config = {\n  matcher: ['\u002F((?!_next\u002Fstatic|_next\u002Fimage|favicon.ico).*)'],\n}\n\n### Auth Callback Route\n\nHandle OAuth callback and exchange code for session\n\n**When to use**: Using OAuth providers (Google, GitHub, etc.)\n\n\u002F\u002F app\u002Fauth\u002Fcallback\u002Froute.ts\nimport { createClient } from '@\u002Flib\u002Fsupabase\u002Fserver'\nimport { NextResponse } from 'next\u002Fserver'\n\nexport async function GET(request: Request) {\n  const { searchParams, origin } = new URL(request.url)\n  const code = searchParams.get('code')\n  const next = searchParams.get('next') ?? '\u002F'\n\n  if (code) {\n    const supabase = await createClient()\n    const { error } = await supabase.auth.exchangeCodeForSession(code)\n    if (!error) {\n      return NextResponse.redirect(`${origin}${next}`)\n    }\n  }\n\n  return NextResponse.redirect(`${origin}\u002Fauth\u002Ferror`)\n}\n\n### Server Action Auth\n\nHandle auth operations in Server Actions\n\n**When to use**: Login, logout, or signup from Server Components\n\n\u002F\u002F app\u002Factions\u002Fauth.ts\n'use server'\nimport { createClient } from '@\u002Flib\u002Fsupabase\u002Fserver'\nimport { redirect } from 'next\u002Fnavigation'\nimport { revalidatePath } from 'next\u002Fcache'\n\nexport async function signIn(formData: FormData) {\n  const supabase = await createClient()\n  const { error } = await supabase.auth.signInWithPassword({\n    email: formData.get('email') as string,\n    password: formData.get('password') as string,\n  })\n\n  if (error) {\n    return { error: error.message }\n  }\n\n  revalidatePath('\u002F', 'layout')\n  redirect('\u002Fdashboard')\n}\n\nexport async function signOut() {\n  const supabase = await createClient()\n  await supabase.auth.signOut()\n  revalidatePath('\u002F', 'layout')\n  redirect('\u002F')\n}\n\n### Get User in Server Component\n\nAccess the authenticated user in Server Components\n\n**When to use**: Rendering user-specific content server-side\n\n\u002F\u002F app\u002Fdashboard\u002Fpage.tsx\nimport { createClient } from '@\u002Flib\u002Fsupabase\u002Fserver'\nimport { redirect } from 'next\u002Fnavigation'\n\nexport default async function DashboardPage() {\n  const supabase = await createClient()\n  const { data: { user } } = await supabase.auth.getUser()\n\n  if (!user) {\n    redirect('\u002Flogin')\n  }\n\n  return (\n    \u003Cdiv>\n      \u003Ch1>Welcome, {user.email}\u003C\u002Fh1>\n    \u003C\u002Fdiv>\n  )\n}\n\n## Validation Checks\n\n### Using getSession() for Auth Checks\n\nSeverity: ERROR\n\nMessage: getSession() doesn't verify the JWT. Use getUser() for secure auth checks.\n\nFix action: Replace getSession() with getUser() for security-critical checks\n\n### OAuth Without Callback Route\n\nSeverity: ERROR\n\nMessage: Using OAuth but missing callback route at app\u002Fauth\u002Fcallback\u002Froute.ts\n\nFix action: Create app\u002Fauth\u002Fcallback\u002Froute.ts to handle OAuth redirects\n\n### Browser Client in Server Context\n\nSeverity: ERROR\n\nMessage: Browser client used in server context. Use createServerClient instead.\n\nFix action: Import and use createServerClient from @supabase\u002Fssr\n\n### Protected Routes Without Middleware\n\nSeverity: WARNING\n\nMessage: No middleware.ts found. Consider adding middleware for route protection.\n\nFix action: Create middleware.ts to protect routes and refresh sessions\n\n### Hardcoded Auth Redirect URL\n\nSeverity: WARNING\n\nMessage: Hardcoded localhost redirect. Use origin for environment flexibility.\n\nFix action: Use window.location.origin or process.env.NEXT_PUBLIC_SITE_URL\n\n### Auth Call Without Error Handling\n\nSeverity: WARNING\n\nMessage: Auth operation without error handling. Always check for errors.\n\nFix action: Destructure { data, error } and handle error case\n\n### Auth Action Without Revalidation\n\nSeverity: WARNING\n\nMessage: Auth action without revalidatePath. Cache may show stale auth state.\n\nFix action: Add revalidatePath('\u002F', 'layout') after auth operations\n\n### Client-Only Route Protection\n\nSeverity: WARNING\n\nMessage: Client-side route protection shows flash of content. Use middleware.\n\nFix action: Move protection to middleware.ts for better UX\n\n## Collaboration\n\n### Delegation Triggers\n\n- database|rls|queries|tables -> supabase-backend (Auth needs database layer)\n- route|page|component|layout -> nextjs-app-router (Auth needs Next.js patterns)\n- deploy|production|vercel -> vercel-deployment (Auth needs deployment config)\n- ui|form|button|design -> frontend (Auth needs UI components)\n\n### Full Auth Stack\n\nSkills: nextjs-supabase-auth, supabase-backend, nextjs-app-router, vercel-deployment\n\nWorkflow:\n\n```\n1. Database setup (supabase-backend)\n2. Auth implementation (nextjs-supabase-auth)\n3. Route protection (nextjs-app-router)\n4. Deployment config (vercel-deployment)\n```\n\n### Protected SaaS\n\nSkills: nextjs-supabase-auth, stripe-integration, supabase-backend\n\nWorkflow:\n\n```\n1. User authentication (nextjs-supabase-auth)\n2. Customer sync (stripe-integration)\n3. Subscription gating (supabase-backend)\n```\n\n## Related Skills\n\nWorks well with: `nextjs-app-router`, `supabase-backend`\n\n## When to Use\n- User mentions or implies: supabase auth next\n- User mentions or implies: authentication next.js\n- User mentions or implies: login supabase\n- User mentions or implies: auth middleware\n- User mentions or implies: protected route\n- User mentions or implies: auth callback\n- User mentions or implies: session management\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.\n","","imported","https:\u002F\u002Fgithub.com\u002Fsickn33\u002Fantigravity-awesome-skills","user_system_seed","SkillOPIC",true,199,697,"2026-05-16 13:30:56",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":32,"skillCount":33,"createdAt":26},"前端开发","frontend","mdi-language-html5","HTML\u002FCSS\u002FJavaScript\u002F框架相关",1,96,[35],{"id":36,"skillId":4,"version":37,"fileName":38,"fileSize":39,"filePath":40,"fileHash":41,"manifest":42,"createdAt":19},"6e2f67d2-f2e6-4cce-bfd7-26fdc7197e84","1.0.0","nextjs-supabase-auth.zip",2738,"uploads\u002Fskills\u002Fc8a4b2a5-b8e8-4d71-a85c-28afa9a5ef78\u002Fnextjs-supabase-auth.zip","30be15dbe2ab776d7b3283bd78e8b5014cc8239d42a65a000fc04d9745fc311a","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":8001}]",{"code":44,"message":45,"data":46},200,"success",{"items":47,"stats":48,"page":51},[],{"averageRating":49,"totalRatings":49,"ratingCounts":50},0,[49,49,49,49,49],{"limit":52,"offset":49,"hasMore":53,"nextOffset":52,"ratedOnly":16},15,false]