Supabase Auth 與 Next.js App Router 的專業整合方案
Next.js + Supabase Auth
Supabase Auth 與 Next.js App Router 的專業整合方案
Capabilities
- nextjs-auth
- supabase-auth-nextjs
- auth-middleware
- auth-callback
Prerequisites
- 必要技能:nextjs-app-router, supabase-backend
Patterns
Supabase Client 設定
針對不同情境建立設定正確的 Supabase Client
使用時機:在 Next.js 專案中設定身分驗證
// lib/supabase/client.ts (瀏覽器端 Client)
'use client'
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
// lib/supabase/server.ts (伺服器端 Client)
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) {
cookiesToSet.forEach(({ name, value, options }) => {
cookieStore.set(name, value, options)
})
},
},
}
)
}
Auth Middleware
在 Middleware 中保護路由並自動刷新 Session
使用時機:需要進行路由權限控管或 Session 自動刷新
// middleware.ts
import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
export async function middleware(request: NextRequest) {
let response = 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, options }) => {
response.cookies.set(name, value, options)
})
},
},
}
)
// 若 Session 已過期則自動更新
const { data: { user } } = await supabase.auth.getUser()
// 保護 dashboard 路由
if (request.nextUrl.pathname.startsWith('/dashboard') && !user) {
return NextResponse.redirect(new URL('/login', request.url))
}
return response
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}
Auth Callback 路由
處理 OAuth 回呼並將驗證碼(code)兌換為 Session
使用時機:整合 OAuth 第三方登入(Google、GitHub 等)
// app/auth/callback/route.ts
import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url)
const code = searchParams.get('code')
const next = searchParams.get('next') ?? '/'
if (code) {
const supabase = await createClient()
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
return NextResponse.redirect(`${origin}${next}`)
}
}
return NextResponse.redirect(`${origin}/auth/error`)
}
Server Action 驗證處理
在 Server Actions 中執行身分驗證相關操作
使用時機:從 Server Components 進行登入、登出或註冊
// app/actions/auth.ts
'use server'
import { createClient } from '@/lib/supabase/server'
import { redirect } from 'next/navigation'
import { revalidatePath } from 'next/cache'
export async function signIn(formData: FormData) {
const supabase = await createClient()
const { error } = await supabase.auth.signInWithPassword({
email: formData.get('email') as string,
password: formData.get('password') as string,
})
if (error) {
return { error: error.message }
}
revalidatePath('/', 'layout')
redirect('/dashboard')
}
export async function signOut() {
const supabase = await createClient()
await supabase.auth.signOut()
revalidatePath('/', 'layout')
redirect('/')
}
在 Server Component 取得使用者資料
在 Server Components 中讀取已登入的使用者資訊
使用時機:要在伺服器端渲染特定使用者的專屬內容
// app/dashboard/page.tsx
import { createClient } from '@/lib/supabase/server'
import { redirect } from 'next/navigation'
export default async function DashboardPage() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
redirect('/login')
}
return (
<div>
<h1>Welcome, {user.email}</h1>
</div>
)
}
Validation Checks
使用 getSession() 進行驗證檢查
嚴重程度:ERROR
錯誤訊息:getSession() 不會驗證 JWT。請改用 getUser() 來確保身分驗證檢查的安全性。
修復動作:在關鍵的安全檢查中,將 getSession() 替換為 getUser()
缺少 OAuth Callback 路由
嚴重程度:ERROR
錯誤訊息:使用了 OAuth 登入但缺少 app/auth/callback/route.ts 回呼路由
修復動作:建立 app/auth/callback/route.ts 來處理 OAuth 的重導向邏輯
在伺服器端環境誤用 Browser Client
嚴重程度:ERROR
錯誤訊息:在 Server 環境使用了 Browser Client。請改用 createServerClient。
修復動作:從 @supabase/ssr 匯入並使用 createServerClient
受保護路由未設定 Middleware
嚴重程度:WARNING
錯誤訊息:未找到 middleware.ts。建議加入 Middleware 以實現路由保護。
修復動作:建立 middleware.ts 來保護受限制路由並刷新 Session
硬編碼的 Auth 重導向 URL
嚴重程度:WARNING
錯誤訊息:重導向使用了硬編碼的 localhost。請改用 origin 以提升不同環境下的彈性。
修復動作:改用 window.location.origin 或 process.env.NEXT_PUBLIC_SITE_URL
Auth 呼叫未處理錯誤
嚴重程度:WARNING
錯誤訊息:執行 Auth 操作時缺少錯誤處理。請務必檢查是否回傳錯誤。
修復動作:透過解構取得 { data, error } 並加入錯誤處理邏輯
Auth Action 未刷新快取
嚴重程度:WARNING
錯誤訊息:Auth Action 操作後未呼叫 revalidatePath,導致快取仍顯示過期的驗證狀態。
修復動作:在 Auth 操作成功後加上 revalidatePath('/', 'layout')
純前端(Client-Side)路由保護
嚴重程度:WARNING
錯誤訊息:僅在客戶端做路由保護會導致畫面閃爍(Flash of Content)。建議改用 Middleware。
修復動作:將保護邏輯移至 middleware.ts 以提供更好的使用者體驗
Collaboration
任務分派觸發條件
- database|rls|queries|tables -> supabase-backend(身分驗證需要資料庫層配合)
- route|page|component|layout -> nextjs-app-router(身分驗證需要 Next.js 開發模式)
- deploy|production|vercel -> vercel-deployment(身分驗證需要正式環境部署設定)
- ui|form|button|design -> frontend(身分驗證需要 UI 元件)
完整 Auth 技術棧流程
Skills: nextjs-supabase-auth, supabase-backend, nextjs-app-router, vercel-deployment
工作流程:
1. 資料庫建置 (supabase-backend)
2. 身分驗證實作 (nextjs-supabase-auth)
3. 路由權限保護 (nextjs-app-router)
4. 部署參數設定 (vercel-deployment)
受保護的 SaaS 應用流程
Skills: nextjs-supabase-auth, stripe-integration, supabase-backend
工作流程:
1. 使用者身分驗證 (nextjs-supabase-auth)
2. 客戶資料同步 (stripe-integration)
3. 訂閱權限控管 (supabase-backend)
Related Skills
適合搭配:nextjs-app-router, supabase-backend
使用時機
- 使用者提及或暗示:supabase auth next
- 使用者提及或暗示:authentication next.js
- 使用者提及或暗示:login supabase
- 使用者提及或暗示:auth middleware
- 使用者提及或暗示:protected route
- 使用者提及或暗示:auth callback
- 使用者提及或暗示:session management
Limitations
- 僅在任務需求明確符合上述涵蓋範疇時使用此 Skill。
- 請勿將產出結果直接取代特定環境下的實際驗證、測試或專家審查。
- 若缺乏必要的輸入資料、執行權限、安全邊界或成功判定標準,請立即暫停並要求進一步說明。






