To secure a Nuxt + Supabase stack, you need to: (1) configure @nuxtjs/supabase module with proper redirect options, (2) use serverSupabaseClient and serverSupabaseUser in server routes, (3) enable RLS on all tables as defense-in-depth, (4) keep the service key server-side only in runtimeConfig, and (5) verify auth in all server API routes. This blueprint covers Nuxt 3 server routes with Supabase integration.
TL;DR
Nuxt with @nuxtjs/supabase provides great DX but requires understanding server vs client contexts. Key tasks: use serverSupabaseClient in API routes, enable RLS on all tables, protect server routes with middleware, and use useSupabaseUser() for reactive auth state on the client.
Module Configuration Nuxt
export default defineNuxtConfig({
modules: ['@nuxtjs/supabase'],
supabase: {
redirectOptions: {
login: '/login',
callback: '/confirm',
exclude: ['/', '/about', '/blog/*'],
},
},
runtimeConfig: {
// Server-only
supabaseServiceKey: process.env.SUPABASE_SERVICE_KEY,
public: {
supabaseUrl: process.env.SUPABASE_URL,
supabaseKey: process.env.SUPABASE_ANON_KEY,
},
},
})
Server API Routes Nuxt Supabase
export default defineEventHandler(async (event) => {
const client = await serverSupabaseClient(event)
const user = await serverSupabaseUser(event)
if (!user) {
throw createError({ statusCode: 401, message: 'Unauthorized' })
}
const body = await readBody(event)
const { data, error } = await client.from('posts').insert({
title: body.title,
author_id: user.id, // Use verified user ID
}).select().single()
if (error) throw createError({ statusCode: 400, message: error.message })
return data
})
Route Middleware Nuxt
export default defineNuxtRouteMiddleware((to) => {
const user = useSupabaseUser()
if (!user.value) {
return navigateTo('/login')
}
})
Client middleware is UX only. Always verify auth server-side in API routes. RLS provides the actual security layer for database access.
Security Checklist
Pre-Launch Checklist
RLS enabled on all tables
Auth verified in all server routes
serverSupabaseClient used server-side
Service key never exposed to client
Environment variables configured
Alternative Stacks
Consider these related blueprints:
- Vue + Supabase - Client-only SPA version
- Next.js + Supabase + Vercel - React/Next.js alternative
- SvelteKit + Supabase - Svelte alternative