{"id":"5879cba0-2e71-4732-9fe4-663e426948cd","shortId":"mBrqmT","kind":"skill","title":"nextjs-supabase-auth","tagline":"Expert integration of Supabase Auth with Next.js App Router","description":"# 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// lib/supabase/client.ts (Browser client)\n'use client'\nimport { createBrowserClient } from '@supabase/ssr'\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// lib/supabase/server.ts (Server client)\nimport { createServerClient } from '@supabase/ssr'\nimport { cookies } from 'next/headers'\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// middleware.ts\nimport { createServerClient } from '@supabase/ssr'\nimport { NextResponse, type NextRequest } from 'next/server'\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  // Refresh session if expired\n  const { data: { user } } = await supabase.auth.getUser()\n\n  // Protect dashboard routes\n  if (request.nextUrl.pathname.startsWith('/dashboard') && !user) {\n    return NextResponse.redirect(new URL('/login', request.url))\n  }\n\n  return response\n}\n\nexport const config = {\n  matcher: ['/((?!_next/static|_next/image|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// app/auth/callback/route.ts\nimport { createClient } from '@/lib/supabase/server'\nimport { NextResponse } from 'next/server'\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') ?? '/'\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}/auth/error`)\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// app/actions/auth.ts\n'use server'\nimport { createClient } from '@/lib/supabase/server'\nimport { redirect } from 'next/navigation'\nimport { revalidatePath } from 'next/cache'\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('/', 'layout')\n  redirect('/dashboard')\n}\n\nexport async function signOut() {\n  const supabase = await createClient()\n  await supabase.auth.signOut()\n  revalidatePath('/', 'layout')\n  redirect('/')\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// app/dashboard/page.tsx\nimport { createClient } from '@/lib/supabase/server'\nimport { redirect } from 'next/navigation'\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('/login')\n  }\n\n  return (\n    <div>\n      <h1>Welcome, {user.email}</h1>\n    </div>\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/auth/callback/route.ts\n\nFix action: Create app/auth/callback/route.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/ssr\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('/', '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.","tags":["nextjs","supabase","auth","antigravity","awesome","skills","sickn33","agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding"],"capabilities":["skill","source-sickn33","skill-nextjs-supabase-auth","topic-agent-skills","topic-agentic-skills","topic-ai-agent-skills","topic-ai-agents","topic-ai-coding","topic-ai-workflows","topic-antigravity","topic-antigravity-skills","topic-claude-code","topic-claude-code-skills","topic-codex-cli","topic-codex-skills"],"categories":["antigravity-awesome-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/nextjs-supabase-auth","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add sickn33/antigravity-awesome-skills","source_repo":"https://github.com/sickn33/antigravity-awesome-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 35034 github stars · SKILL.md body (7,812 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-25T12:51:06.309Z","embedding":null,"createdAt":"2026-04-18T20:27:25.889Z","updatedAt":"2026-04-25T12:51:06.309Z","lastSeenAt":"2026-04-25T12:51:06.309Z","tsv":"'/auth/error':305 '/dashboard':219,372 '/lib/supabase/server':260,331,413 '/login':225,435 '1':713,753 '2':719,760 '3':726,766 '4':733 'access':391 'action':307,314,462,488,513,537,562,588,597,604,614,641 'ad':531 'add':615 'alway':583 'anon':93,123,189 'app':12,24,45,669,707,731,779 'app/actions/auth.ts':325 'app/auth/callback/route.ts':256,486,490 'app/dashboard/page.tsx':409 'ask':863 'async':107,170,266,341,374,420 'auth':4,9,16,21,29,32,35,38,67,139,236,308,310,444,459,547,570,578,596,603,611,619,659,671,681,690,695,701,720,725,745,759,792,810,822 'auth-callback':37 'auth-middlewar':34 'authent':393,755,798 'await':112,212,289,293,348,352,379,381,425,430 'backend':49,658,704,718,751,771,783 'better':647 'boundari':871 'browser':73,495,503 'button':687 'cach':607 'call':571 'callback':39,237,241,474,483,823 'capabl':26 'case':595 'check':440,445,460,471,584 'clarif':865 'clear':838 'client':52,58,74,76,97,496,504,622,630 'client-on':621 'client-sid':629 'code':244,278,280,286,295 'collabor':649 'compon':324,390,397,665,693 'config':231,684,735 'configur':56 'consid':530 'const':110,179,209,230,271,277,281,287,291,346,350,377,423,427 'content':405,637 'context':61,499,508 'cooki':103,113,125,191 'cookiestor':111 'cookiestore.getall':128 'cookiestore.set':135 'cookiestoset':130,196 'cookiestoset.foreach':131,197 'creat':54,489,538 'createbrowsercli':78,85 'createcli':83,109,258,290,329,349,380,411,426 'createservercli':99,115,160,181,510,517 'criteria':874 'critic':470 'custom':761 'dashboard':215 'dashboardpag':422 'data':210,428,590 'databas':652,661,714 'default':419 'deleg':650 'deploy':675,680,683,711,734,738 'describ':842 'design':688 'destructur':589 'differ':60 'doesn':450 'email':354,356 'environ':559,854 'environment-specif':853 'error':292,297,351,365,367,447,477,501,573,581,586,591,594 'error.message':368 'etc':255 'exchang':243 'expert':5,17,859 'expir':208 'export':81,106,169,229,265,340,373,418 'favicon.ico':235 'fix':461,487,512,536,561,587,613,640 'flash':635 'flexibl':560 'form':686 'formdata':344,345 'formdata.get':355,360 'found':529 'frontend':689 'full':694 'function':82,108,171,267,342,375,421 'gate':768 'get':268,386 'getal':126,192 'getsess':442,449,464 'getus':456,466 'github':254 'googl':253 'handl':239,309,492,574,582,593 'hardcod':546,553 'implement':721 'impli':790,797,803,809,815,821,827 'import':77,98,102,159,163,257,261,328,332,336,410,414,514 'input':868 'instead':511 'integr':6,18,748,765 'jwt':454 'key':94,124,190 'layer':662 'layout':370,384,617,666 'let':175 'lib/supabase/client.ts':72 'lib/supabase/server.ts':95 'limit':830 'localhost':554 'login':318,804 'logout':319 'manag':829 'match':839 'matcher':232 'may':608 'mention':788,795,801,807,813,819,825 'messag':448,478,502,526,552,577,602,628 'middlewar':36,140,147,172,523,532,639,811 'middleware.ts':158,528,539,645 'miss':482,876 'move':642 'name':132,136,198,202 'need':152,660,672,682,691 'new':223,274 'next':282,284,301,793 'next.js':11,14,23,70,673,799 'next/cache':339 'next/headers':105 'next/image':234 'next/navigation':335,417 'next/server':168,264 'next/static':233 'nextj':2,28,33,44,668,699,706,723,730,743,757,778 'nextjs-app-rout':43,667,705,729,777 'nextjs-auth':27 'nextjs-supabase-auth':1,698,722,742,756 'nextrequest':166,174 'nextrespons':164,262 'nextresponse.next':177 'nextresponse.redirect':222,299,303 'oauth':240,251,472,480,493 'oper':311,579,620 'option':134,138,200,204 'origin':273,300,304,557 'output':848 'page':664 'password':359,361 'pattern':50,674 'permiss':869 'prerequisit':40 'process.env.next':86,90,116,120,182,186,566 'product':676 'project':71 'proper':55 'protect':141,154,214,520,535,541,625,633,643,728,739,816 'provid':252 'public':87,91,117,121,183,187,567 'queri':654 'redirect':333,371,385,415,434,494,548,555 'refresh':144,157,205,544 'relat':772 'render':401 'replac':463 'request':173,178,269,270 'request.cookies.getall':194 'request.nexturl.pathname.startswith':218 'request.url':226,276 'requir':41,867 'respons':176,228 'response.cookies.set':201 'return':84,114,127,193,221,227,298,302,366,436 'revalid':599 'revalidatepath':337,369,383,606,616 'review':860 'rls':653 'rout':142,153,216,238,475,484,521,534,542,624,632,663,727,817 'router':13,25,46,670,708,732,780 'saa':740 'safeti':870 'scope':841 'searchparam':272 'searchparams.get':279,283 'secur':458,469 'security-crit':468 'server':96,306,313,323,327,389,396,407,498,507 'server-sid':406 'session':145,156,206,246,545,828 'set':65 'setal':129,195 'setup':53,715 'sever':446,476,500,524,550,575,600,626 'show':609,634 'side':408,631 'signin':343 'signout':376 'signup':321 'site':568 'skill':42,697,741,773,833 'skill-nextjs-supabase-auth' 'source-sickn33' 'specif':404,855 'stack':696 'stale':610 'state':612 'stop':861 'string':358,363 'stripe':747,764 'stripe-integr':746,763 'subscript':767 'substitut':851 'success':873 'supabas':3,8,15,20,31,48,51,57,88,92,118,122,180,184,188,288,347,378,424,657,700,703,717,724,744,750,758,770,782,791,805 'supabase-auth-nextj':30 'supabase-backend':47,656,702,716,749,769,781 'supabase.auth.exchangecodeforsession':294 'supabase.auth.getuser':213,431 'supabase.auth.signinwithpassword':353 'supabase.auth.signout':382 'supabase/ssr':80,101,162,519 'sync':762 'tabl':655 'task':837 'test':857 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agent-skills' 'topic-ai-agents' 'topic-ai-coding' 'topic-ai-workflows' 'topic-antigravity' 'topic-antigravity-skills' 'topic-claude-code' 'topic-claude-code-skills' 'topic-codex-cli' 'topic-codex-skills' 'treat':846 'trigger':651 'type':165 'ui':685,692 'url':89,119,185,224,275,549,569 'use':64,75,150,249,250,317,326,400,441,455,479,505,509,516,556,563,638,786,831 'user':211,220,387,394,403,429,433,754,787,794,800,806,812,818,824 'user-specif':402 'user.email':438 'ux':648 'valid':439,856 'valu':133,137,199,203 'vercel':677,679,710,737 'vercel-deploy':678,709,736 'verifi':452 'warn':525,551,576,601,627 'welcom':437 'well':775 'window.location.origin':564 'without':473,522,572,580,598,605 'work':774 'workflow':712,752","prices":[{"id":"74ea7a59-cd9d-4aea-843c-8476a514c5df","listingId":"5879cba0-2e71-4732-9fe4-663e426948cd","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"sickn33","category":"antigravity-awesome-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T20:27:25.889Z"}],"sources":[{"listingId":"5879cba0-2e71-4732-9fe4-663e426948cd","source":"github","sourceId":"sickn33/antigravity-awesome-skills/nextjs-supabase-auth","sourceUrl":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/nextjs-supabase-auth","isPrimary":false,"firstSeenAt":"2026-04-18T21:41:24.958Z","lastSeenAt":"2026-04-25T12:51:06.309Z"},{"listingId":"5879cba0-2e71-4732-9fe4-663e426948cd","source":"skills_sh","sourceId":"sickn33/antigravity-awesome-skills/nextjs-supabase-auth","sourceUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/nextjs-supabase-auth","isPrimary":true,"firstSeenAt":"2026-04-18T20:27:25.889Z","lastSeenAt":"2026-04-25T12:40:16.186Z"}],"details":{"listingId":"5879cba0-2e71-4732-9fe4-663e426948cd","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"sickn33","slug":"nextjs-supabase-auth","github":{"repo":"sickn33/antigravity-awesome-skills","stars":35034,"topics":["agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity","antigravity-skills","claude-code","claude-code-skills","codex-cli","codex-skills","cursor","cursor-skills","developer-tools","gemini-cli","gemini-skills","kiro","mcp","skill-library"],"license":"mit","html_url":"https://github.com/sickn33/antigravity-awesome-skills","pushed_at":"2026-04-25T06:33:17Z","description":"Installable GitHub library of 1,400+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and more. Includes installer CLI, bundles, workflows, and official/community skill collections.","skill_md_sha":"31d597634e45a1ff91ba31d42af7ba46d59d85db","skill_md_path":"skills/nextjs-supabase-auth/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/nextjs-supabase-auth"},"layout":"multi","source":"github","category":"antigravity-awesome-skills","frontmatter":{"name":"nextjs-supabase-auth","description":"Expert integration of Supabase Auth with Next.js App Router"},"skills_sh_url":"https://skills.sh/sickn33/antigravity-awesome-skills/nextjs-supabase-auth"},"updatedAt":"2026-04-25T12:51:06.309Z"}}