← Guias
5 min de leitura

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.