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-dev

Passo 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>