Manual: Autenticação com Nuxt
O guia completo com o módulo @nuxtjs/supabase.
Passo 1: Criação do Projeto
Inicie um projeto Nuxt 3 e instale o módulo oficial do Supabase. O módulo cuidará de grande parte da configuração para nós.
# 1. Crie o projeto
npx nuxi@latest init meu-app-nuxt
# 2. Entre na pasta
cd meu-app-nuxt
# 3. Instale o módulo Supabase
npm install @nuxtjs/supabase --save-devPasso 2: Configuração do Módulo
A configuração é feita de forma centralizada no arquivo nuxt.config.ts. Adicione o módulo e suas chaves do Supabase.
📄 nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nuxtjs/supabase'
],
supabase: {
// URL do seu projeto Supabase
url: 'SUA_PROJECT_URL_AQUI',
// Chave ANÔNIMA PÚBLICA do seu projeto
key: 'SUA_ANON_KEY_AQUI',
// Opções de redirecionamento
redirectOptions: {
login: '/login', // Para onde redirecionar se o usuário não estiver logado
callback: '/confirm', // Rota de confirmação de email
exclude: ['/register'], // Rotas que não precisam de autenticação
}
}
})Passo 3: Middlewares de Proteção
Middlewares são a forma do Nuxt de proteger rotas. Vamos criar dois: um para rotas que exigem login (`auth`) e outro para rotas que só podem ser vistas por visitantes (`guest`).
📄 middleware/auth.ts
// Este middleware verifica se o usuário ESTÁ logado.
export default defineNuxtRouteMiddleware((to, from) => {
const user = useSupabaseUser();
if (!user.value) {
// Se não há usuário, o módulo Supabase já redireciona para /login
// mas podemos adicionar uma lógica extra se quisermos.
// Este middleware é aplicado nas páginas que precisam de login.
return navigateTo('/login');
}
});📄 middleware/guest.ts
// Este middleware verifica se o usuário NÃO está logado.
export default defineNuxtRouteMiddleware((to, from) => {
const user = useSupabaseUser();
if (user.value) {
// Se o usuário já está logado, ele não deve ver a página de login.
// Redirecionamos para o dashboard.
return navigateTo('/dashboard');
}
});Passo 4: Estrutura das Páginas
O Nuxt usa roteamento baseado em arquivos na pasta pages/. Crie esta estrutura para as nossas rotas.
/
└── pages/
├── login.vue
├── register.vue
└── dashboard.vue
Passo 5: Página de Login
Esta página conterá o formulário de login e aplicará o middleware `guest`.
📄 pages/login.vue
<template>
<div class="flex justify-center items-center min-h-screen">
<form @submit.prevent="handleLogin" class="p-8 bg-white rounded shadow-md w-96">
<h2 class="text-2xl font-bold mb-6">Login</h2>
<div class="mb-4">
<input type="email" v-model="email" placeholder="Email" class="w-full p-2 border rounded" />
</div>
<div class="mb-6">
<input type="password" v-model="password" placeholder="Senha" class="w-full p-2 border rounded" />
</div>
<button type="submit" class="w-full bg-green-500 text-white p-2 rounded">Entrar</button>
<p v-if="errorMsg" class="text-red-500 mt-2">{{ errorMsg }}</p>
</form>
</div>
</template>
<script setup>
definePageMeta({ middleware: 'guest' });
const email = ref('');
const password = ref('');
const errorMsg = ref(null);
const client = useSupabaseClient();
const router = useRouter();
async function handleLogin() {
try {
const { error } = await client.auth.signInWithPassword({
email: email.value,
password: password.value,
});
if (error) throw error;
router.push('/dashboard');
} catch (error) {
errorMsg.value = error.message;
}
}
</script>Passo 6: Página de Dashboard
A página protegida que só usuários logados podem ver. Aplicamos o middleware `auth`.
📄 pages/dashboard.vue
<template>
<div class="p-8 text-center">
<h1 class="text-3xl font-bold">Dashboard</h1>
<div v-if="user" class="mt-4">
<p>Bem-vindo, <strong class="text-green-500">{{ user.email }}</strong>!</p>
<button @click="handleLogout" class="mt-6 bg-red-500 text-white py-2 px-4 rounded">Sair</button>
</div>
</div>
</template>
<script setup>
definePageMeta({ middleware: 'auth' });
const user = useSupabaseUser();
const client = useSupabaseClient();
const router = useRouter();
const handleLogout = async () => {
const { error } = await client.auth.signOut();
if (error) console.log(error);
else router.push('/login');
};
</script>Passo 7: Layout Principal da Aplicação
O arquivo app.vue é o ponto de entrada da sua aplicação. Ele renderiza a página da rota atual.
📄 app.vue
<template>
<div>
<NuxtPage />
</div>
</template>