- Artigos
- Desenvolvimento
- Protegendo APIs públicas para que só a sua aplicação consiga consumi-las

Se o seu frontend chama uma API diretamente no navegador, essa API é pública na prática. Qualquer pessoa pode abrir o DevTools, copiar a requisição e repeti-la em um script. Proteger uma API pública não significa torná-la invisível; significa aumentar o custo do abuso mantendo o tráfego legítimo rápido e confiável.
Este artigo foca em defesas realistas para equipes que trabalham com Nuxt, Vue, TypeScript, Laravel e Node.js. O objetivo é simples: o seu produto deve ser o consumidor principal, e scraping casual ou abuso automatizado deve ser caro o suficiente para desencorajar a maioria dos atacantes.
Entenda o que você está protegendo de verdade
Comece separando dois problemas diferentes:
Clientes não autorizados — bots, concorrentes ou scrapers chamando os mesmos endpoints que o seu app usa.
Usuários não autorizados — alguém autenticado em outro contexto tentando acessar dados que não deveria ver.
Autorização de usuário pertence à camada de autenticação. Este texto trata do primeiro caso: impedir que clientes aleatórios tratem sua API como um feed de dados gratuito.
Aceite também uma verdade difícil: tudo que vai para o navegador ou para o app mobile pode ser engenharia reversa. Uma API key estática no frontend, um header escondido ou um User-Agent customizado não é segredo. Trate valores do lado do cliente como identificadores, não como travas.
Coloque leituras sensíveis atrás de um backend-for-frontend
O padrão mais forte para aplicações web é o BFF (backend-for-frontend). Em vez de expor uma API REST ampla ao navegador, as server routes do Nuxt ou um gateway Laravel/Node se tornam a única superfície pública.
O frontend chama /api/products no seu próprio domínio. Esse handler server-side consulta o serviço interno com credencial exclusiva do servidor, aplica regras de negócio, remove campos que não devem vazar e devolve uma resposta modelada. Scrapers passam a bater na sua camada de borda, não no serviço central de dados.
No Nuxt 3, isso encaixa bem em server routes ou server middleware. No Laravel, use controllers dedicados ou um pacote de API gateway. No Node, um proxy Express/Fastify na frente dos serviços internos funciona da mesma forma.
Benefícios:
Segredos ficam no servidor.
Você aplica limites por usuário usando sessão ou contexto de JWT.
Pode mudar APIs internas sem quebrar o contrato do cliente.
Ganha um único ponto para logar, limitar e bloquear comportamento suspeito.
Se a API precisar continuar pública — por exemplo, integração com parceiros ou app mobile com necessidades offline — use o BFF na web e mantenha uma API pública mais enxuta e com escopo restrito para os outros canais.
Use tokens de curta duração e escopo limitado em vez de API keys eternas
Quando o cliente precisa chamar a API diretamente, evite chaves permanentes embutidas no bundle. Prefira tokens de acesso de curta duração emitidos depois que o usuário prova identidade ou conclui um bootstrap do app.
Um fluxo prático:
O app solicita um token de sessão ou de dispositivo no endpoint de autenticação.
O servidor assina um JWT ou token opaco com expiração curta — minutos, não meses.
Cada token carrega apenas os escopos necessários para aquela tela ou ação.
O refresh acontece no servidor ou via refresh token rotacionado, vinculado à sessão do usuário.
No Laravel, Passport ou Sanctum podem emitir tokens com escopo. No Node, use seu provedor de identidade ou assine JWTs com chaves rotacionadas. No Nuxt, busque tokens em uma server route para que o segredo de assinatura nunca chegue ao cliente.
Combine tokens com claims de audience e issuer para que um token criado para o app web não possa ser reutilizado na API administrativa. Rejeite tokens com audience incorreta imediatamente.
Assine requisições quando precisar de vínculo mais forte com o cliente
Tokens provam quem é o usuário. Assinatura de requisições ajuda a demonstrar que a chamada veio do fluxo da sua aplicação, não de um curl copiado.
Uma abordagem comum:
Gere uma chave por instalação ou por sessão durante o bootstrap.
Inclua timestamp, nonce, método HTTP, path e hash do body em uma string canônica.
Assine essa string com HMAC-SHA256 usando um segredo validado no servidor.
Envie os headers
X-Signature,X-TimestampeX-Nonceem cada requisição.
No servidor, valide a assinatura, rejeite timestamps fora de uma janela pequena e armazene nonces recentes para bloquear replay. Isso não impede um atacante determinado para sempre, mas elimina replay ingênuo e a maior parte do abuso por copiar e colar.
Mantenha a lógica de assinatura em um módulo compartilhado entre o server do Nuxt e o app mobile. Nunca envie o segredo mestre de assinatura no JavaScript do frontend. Se o navegador precisar assinar, derive um segredo limitado após uma etapa de atestação no servidor ou faça a assinatura no BFF.
Adicione rate limiting, detecção de anomalias e sinais de abuso
Mesmo criptografia bem feita falha sem controles operacionais. Rate limiting é seu primeiro controle em produção.
Limite por ID de usuário quando autenticado.
Limite por IP mais sinais de fingerprint quando anônimo.
Use buckets mais rígidos para endpoints caros como busca, exportação ou paginação de feed.
Retorne
429 Too Many Requestscom headerRetry-After.
No Laravel, middlewares ou limitadores com Redis funcionam bem. No Node, express-rate-limit com Redis é escolha comum. Na borda, Cloudflare, AWS WAF ou API gateways absorvem tráfego antes de chegar aos seus servidores.
Vá além de contadores. Acompanhe anomalias comportamentais: padrões idênticos de paginação em milhares de IPs, timing impossível de requisições, ausência de headers que você sempre espera ou picos geográficos repentinos em um produto local. Alerte primeiro, depois desafie ou bloqueie.
Não confunda CORS, checagem de referrer ou ofuscação com segurança
Equipes frequentemente dependem de controles que só afetam navegadores, não atacantes:
CORS impede que o JavaScript de outro site leia sua resposta. Não bloqueia scripts server-side, apps mobile ou Postman.
Checagens de Referer/Origin são sinal fraco, não mecanismo de autorização. Headers podem ser falsificados fora do navegador.
Ofuscação — paths minificados, headers customizados, esconder complexidade no GraphQL — só atrasa a descoberta um pouco.
Use CORS corretamente para proteger usuários contra roubo cross-site de dados, mas nunca trate isso como controle de acesso à API. Aplicação real acontece no servidor com credenciais, assinaturas, escopos e limites.
Endurecimento específico para mobile e server-to-server
Apps mobile enfrentam o mesmo risco de extração que SPAs, mas você pode adicionar atestação de app no iOS e Android para que o backend só emita tokens para builds legítimos. Combine atestação com tokens de curta duração e limites por dispositivo.
Para tráfego server-to-server — workers de fila no Laravel, crons em Node, ETL interno — use mTLS ou caminhos de rede privada. Exposição na internet pública deve ser exceção. Rotacione credenciais de serviço automaticamente e mapeie cada credencial a uma identidade de serviço única.
Um checklist pragmático de arquitetura
Antes de publicar, percorra esta lista:
Endpoints de leitura que alimentam a UI passam por um BFF com segredos só no servidor?
Clientes usam tokens de curta duração e escopo limitado em vez de API keys permanentes?
Rotas de alto valor têm proteção com HMAC ou resistência equivalente a replay?
Rate limits são aplicados por usuário, IP e classe de rota?
Logs incluem request ID, versão do cliente e subject de autenticação para investigação?
Você consegue revogar credencial comprometida sem redeployar o frontend inteiro?
Você não vai construir uma API que somente sua aplicação consiga ler em termos absolutos. Mas pode construir uma em que seu app seja o único cliente que lê com eficiência, legalidade e escala, enquanto todos os outros encontram atrito em cada camada. Esse é o padrão prático que vale colocar em produção.