Implementando autenticação segura com Supabase Auth e RLS. Protegendo dados no nível de banco de dados com políticas granulares.
Ednei Trabach
Desenvolvedor Full Stack
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.
npm install @supabase/supabase-js
// 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)
async function signUp(email: string, password: string) {
const { data, error } = await supabase.auth.signUp({
email,
password,
})
if (error) throw error
return data
}
async function signIn(email: string, password: string) {
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
})
if (error) throw error
return data
}
async function signOut() {
const { error } = await supabase.auth.signOut()
if (error) throw error
}
O RLS permite definir políticas de acesso no PostgreSQL que são automaticamente aplicadas:
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
-- 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);
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);
<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>
// Não confie apenas no frontend
const { data: { user } } = await supabase.auth.getUser()
if (!user) throw new Error('Não autenticado')
// Nunca expor service_role key no frontend
const supabaseAdmin = createClient(
url,
serviceRoleKey, // ⚠️ Backend apenas
{ auth: { persistSession: false } }
)
-- 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);
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.