EDNEI
EDNEITRABACH
>Início>Projetos>Experiência>Sobre>Blog
GitHubLinkedInInstagram
status: disponível
>Início>Projetos>Experiência>Sobre>Blog
status: disponível

Conecte-se

Vamos construir algo junto

Sempre interessado em colaborações, problemas interessantes e conversas sobre código, design e tudo mais.

enviar mensagem→

Me encontre também

GitHub
@EdneiTrabach
LinkedIn
/in/edneitrabach
Instagram
@edneitrabach
WhatsApp
Conversar
Desenvolvido com& código

© 2026 EdneiTrabach — All experiments reserved

back to blog
backendfeatured

Supabase: Autenticação e Row Level Security na Prática

Implementando autenticação segura com Supabase Auth e RLS. Protegendo dados no nível de banco de dados com políticas granulares.

ET

Ednei Trabach

Desenvolvedor Full Stack

10 de janeiro de 202512 min read
#supabase#postgresql#authentication#security

Por que Supabase?

Supabase combina PostgreSQL, autenticação e storage em uma única plataforma. O que mais me impressiona é o Row Level Security (RLS) - segurança no nível de banco de dados que simplifica muito a lógica de autorização em aplicações.

Configuração Inicial

1. Criar projeto Supabase

npm install @supabase/supabase-js

2. Configurar cliente

// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!

export const supabase = createClient(supabaseUrl, supabaseKey)

Autenticação com Supabase Auth

Cadastro de Usuário

async function signUp(email: string, password: string) {
  const { data, error } = await supabase.auth.signUp({
    email,
    password,
  })

  if (error) throw error
  return data
}

Login

async function signIn(email: string, password: string) {
  const { data, error } = await supabase.auth.signInWithPassword({
    email,
    password,
  })

  if (error) throw error
  return data
}

Logout

async function signOut() {
  const { error } = await supabase.auth.signOut()
  if (error) throw error
}

Row Level Security (RLS)

O RLS permite definir políticas de acesso no PostgreSQL que são automaticamente aplicadas:

Habilitar RLS

ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;

Criar Políticas

-- Usuários só podem ver seu próprio perfil
CREATE POLICY "Users can view own profile"
ON profiles
FOR SELECT
USING (auth.uid() = id);

-- Usuários só podem atualizar seu próprio perfil
CREATE POLICY "Users can update own profile"
ON profiles
FOR UPDATE
USING (auth.uid() = id);

-- Usuários podem inserir apenas com seu próprio ID
CREATE POLICY "Users can insert own profile"
ON profiles
FOR INSERT
WITH CHECK (auth.uid() = id);

Exemplo Prático: Sistema de Tarefas

Tabela de Tarefas

CREATE TABLE tasks (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  user_id UUID REFERENCES auth.users(id) NOT NULL,
  title TEXT NOT NULL,
  completed BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;

-- Política para ver tarefas do usuário
CREATE POLICY "Users can view own tasks"
ON tasks
FOR SELECT
USING (auth.uid() = user_id);

-- Política para criar tarefas
CREATE POLICY "Users can create tasks"
ON tasks
FOR INSERT
WITH CHECK (auth.uid() = user_id);

-- Política para atualizar tarefas
CREATE POLICY "Users can update own tasks"
ON tasks
FOR UPDATE
USING (auth.uid() = user_id);

-- Política para deletar tarefas
CREATE POLICY "Users can delete own tasks"
ON tasks
FOR DELETE
USING (auth.uid() = user_id);

Frontend com Vue.js

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { supabase } from '@/lib/supabase'

const tasks = ref([])
const newTask = ref('')

async function fetchTasks() {
  const { data, error } = await supabase
    .from('tasks')
    .select('*')
    .order('created_at', { ascending: false })

  if (error) console.error(error)
  else tasks.value = data
}

async function addTask() {
  const { error } = await supabase
    .from('tasks')
    .insert({
      title: newTask.value,
      user_id: (await supabase.auth.getUser()).data.user?.id
    })

  if (error) console.error(error)
  else {
    newTask.value = ''
    fetchTasks()
  }
}

async function toggleComplete(task: any) {
  const { error } = await supabase
    .from('tasks')
    .update({ completed: !task.completed })
    .eq('id', task.id)

  if (error) console.error(error)
  else fetchTasks()
}

onMounted(() => {
  fetchTasks()
})
</script>

Boas Práticas

1. Sempre validar no backend

// Não confie apenas no frontend
const { data: { user } } = await supabase.auth.getUser()
if (!user) throw new Error('Não autenticado')

2. Use service role apenas no backend

// Nunca expor service_role key no frontend
const supabaseAdmin = createClient(
  url,
  serviceRoleKey, // ⚠️ Backend apenas
  { auth: { persistSession: false } }
)

3. Criar políticas granulares

-- Políticas específicas são melhores que políticas genéricas
CREATE POLICY "Users can view completed tasks"
ON tasks
FOR SELECT
USING (auth.uid() = user_id AND completed = true);

Conclusão

Supabase + RLS simplificam drasticamente a autenticação e autorização. Na minha experiência com o Financial Control, essa abordagem reduziu significativamente o código de autorização e melhorou a segurança da aplicação.

A segurança no nível de banco de dados significa que mesmo que alguém comprometa o frontend, os dados permanecem protegidos.

share
share: