Rota de API sem login: o risco e como proteger no Next.js, no Express e no Supabase
A rota que grava no banco, apaga arquivos ou chama uma IA precisa conferir quem chama. Sem isso, qualquer um usa — e a conta vem para você. Exemplos de como proteger.
Endereço de rota não é segredo. Ele aparece no JavaScript do site, na aba de rede do navegador e em qualquer ferramenta que liste as chamadas. Se a rota não confere quem está chamando, ela é pública — mesmo que nenhuma tela a mostre.
Quais rotas precisam de login
- As que gravam, alteram ou apagam no banco.
- As que chamam serviço cobrado por uso: IA, envio de e-mail ou SMS.
- As que enviam, apagam ou listam arquivos privados.
- As que executam comandos no servidor.
Formulário de contato, cadastro e webhook são públicos por natureza — mas cada um tem a sua proteção: limite de envios, CAPTCHA, e o webhook confere a assinatura de quem o envia.
Next.js (App Router) com Supabase
import { createClient } from "@/lib/supabase/server";
export async function POST(req: Request) {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
if (!user) return Response.json({ erro: "faça login" }, { status: 401 });
// daqui para baixo, só quem está logado — e use user.id, não um id do corpo
}Express
// o middleware confere o token e recusa antes de chegar na rota
app.post("/api/pedidos", exigirLogin, async (req, res) => {
await criarPedido({ ...req.body, dono: req.usuario.id });
res.json({ ok: true });
});Edge Function do Supabase
Por padrão, as Edge Functions só conferem se o pedido traz um JWT — e a chave pública antiga (anon) também é um JWT. Dentro da função, confira o usuário com supabase.auth.getUser() usando o cabeçalho Authorization do pedido, e recuse quando não houver usuário.
Esconder o botão na tela não protege a rota. Quem ataca não usa as suas telas: chama a rota direto.
Dicas curtas de segurança para quem cria com IA: siga @npx_vibedefender no Instagram.