Authentication that ships.
mbl-auth wraps Supabase with a production-ready Nuxt 4 module: SSR-safe sessions, role-based middleware, and a full admin API โ drop it in and move on.
Install
npm install @madebylars.com/mbl-authWhat you get
SSR sessions via cookies
Uses @supabase/ssr for secure, server-rendered session handling. No localStorage leaking on first render.
Role-based access control
Configurable roles stored in Supabase user metadata. The admin middleware and hasRole() helper make authorization trivial.
OAuth & magic link
Built-in /confirm callback route handles OAuth redirects and magic links automatically.
Service key stays server-side
The Supabase service role key never reaches the browser. Admin operations only run in server routes.
Admin user management API
GET, PATCH (role), and DELETE endpoints at /api/admin/users. Automatically protected โ only admins can call them.
Auto-imported composables
useSupabaseClient, useSupabaseUser, useSupabaseSession, useSupabaseUserRole โ all available without imports.
Configuration
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@madebylars.com/mbl-auth'],
mblAuth: {
supabaseUrl: process.env.SUPABASE_URL,
supabaseKey: process.env.SUPABASE_ANON_KEY,
supabaseServiceKey: process.env.SUPABASE_SERVICE_KEY,
roles: ['admin', 'user'],
defaultRole: 'user',
redirect: {
login: '/login',
callback: '/confirm',
forbidden: '/forbidden',
},
},
})Composables
<script setup>
// Reactive user & session โ SSR safe
const user = useSupabaseUser()
const session = useSupabaseSession()
const { role, hasRole } = useSupabaseUserRole()
// Auth actions
const supabase = useSupabaseClient()
await supabase.auth.signInWithPassword({ email, password })
await supabase.auth.signOut()
</script>
<template>
<div v-if="user">
Hello {{ user.email }} โ role: {{ role }}
</div>
</template>Route middleware
// Protect any page with a one-liner
definePageMeta({ middleware: 'auth' })
// Restrict to admins only
definePageMeta({ middleware: 'admin' })