Existe uma mensagem de erro que todo desenvolvedor que separa front-end e back-end encontra mais cedo ou mais tarde: o navegador recusa a chamada à API, com uma explicação sobre política de origem que não parece fazer sentido — porque a API está funcionando, e chamá-la por outra ferramenta funciona.
Esse erro não é um defeito. É uma proteção do navegador operando exatamente como deveria. E a forma como você resolve tem consequências que vão além de fazer a chamada passar: ela afeta autenticação, cookies, segurança e a complexidade da sua infraestrutura.
Este guia explica o mecanismo e compara as formas de organizar os endereços.
Por que o navegador bloqueia
O conceito por trás é chamado de política de mesma origem, e ele existe por um motivo concreto.
Uma origem é a combinação de protocolo, domínio e porta. Duas páginas têm a mesma origem quando esses três elementos coincidem exatamente. Qualquer diferença — inclusive entre um domínio e um subdomínio dele — cria origens distintas.
A regra: uma página de uma origem não pode ler livremente respostas de outra origem.
O motivo fica claro com um exemplo. Sem essa proteção, um site malicioso aberto em outra aba poderia fazer chamadas ao sistema do seu banco usando a sua sessão ativa e ler as respostas. A política de mesma origem impede isso.
O mecanismo que permite exceções controladas é o que se costuma chamar de CORS: o servidor de destino declara quais origens têm permissão para ler as respostas dele. Sem essa declaração, o navegador bloqueia — mesmo que a requisição tenha chegado e sido respondida com sucesso.
Dois esclarecimentos que evitam confusão:
- Não é uma proteção do servidor, é do navegador. Chamar a mesma API por outra ferramenta funciona normalmente, porque não há navegador aplicando a regra.
- Permitir uma origem não é uma falha de segurança, desde que seja uma origem que você controla. O problema é permitir qualquer origem indiscriminadamente.
As formas de organizar os endereços
A decisão que determina se você vai lidar com isso ou não:
| Arranjo | Exemplo | Mesma origem? | Precisa de CORS? |
|---|---|---|---|
| Mesmo domínio, caminho diferente | site.com e site.com/api | Sim | Não |
| Subdomínio | site.com e api.site.com | Não | Sim |
| Domínio separado | site.com e outra.com | Não | Sim |
| Portas diferentes | site.com e site.com:3000 | Não | Sim |
A primeira linha é a que resolve o problema pela raiz: se o front-end e a API respondem no mesmo domínio, em caminhos diferentes, não há origens distintas e nada precisa ser configurado.
Isso é feito com um proxy reverso na frente: ele recebe todas as requisições e encaminha internamente — as que começam com um caminho específico vão para a aplicação de back-end, as demais para os arquivos do front-end. Para o navegador, tudo veio do mesmo lugar.
A última linha costuma surpreender: portas diferentes são origens diferentes, o que explica por que o erro aparece em desenvolvimento mesmo com tudo rodando na mesma máquina.
Comparando os arranjos
Cada um tem vantagens reais, e a escolha não é óbvia.
Mesmo domínio, via proxy
A favor: sem configuração de origens cruzadas, cookies funcionam naturalmente, um único certificado, uma configuração a menos para manter errada.
Contra: exige um proxy reverso configurado, e front-end e back-end ficam acoplados no mesmo ponto de entrada.
Subdomínio para a API
A favor: separação clara, possibilidade de hospedar cada parte em lugares diferentes, escalabilidade independente.
Contra: exige configuração de origens permitidas, e cookies precisam de atenção especial — embora subdomínios do mesmo domínio principal tenham mais opções que domínios totalmente distintos.
Domínio separado
A favor: independência total, útil quando a API atende vários produtos ou clientes.
Contra: a configuração mais trabalhosa, com as maiores restrições para cookies e autenticação.
A recomendação prática: para um produto único, o mesmo domínio via proxy é o arranjo mais simples e com menos pontos de falha. Subdomínio faz sentido quando as partes precisam ser hospedadas ou escaladas de forma independente. Domínio separado, quando a API é um produto por si só.
Autenticação: onde a decisão pesa
O ponto que transforma uma escolha de organização em uma decisão de arquitetura.
Existem duas formas comuns de manter a sessão de um usuário, e elas reagem de forma diferente à separação de origens:
Cookies. São enviados automaticamente pelo navegador e podem ser configurados de modo que o código da página não consiga lê-los, o que os protege contra uma classe de ataques. Mas o comportamento entre origens diferentes é restritivo: navegadores vêm limitando progressivamente o envio de cookies entre sites distintos.
Credencial guardada pela aplicação. O código guarda um identificador de sessão e o envia manualmente a cada chamada. Funciona entre quaisquer origens, mas o valor fica acessível ao código da página — e, se houver uma falha que permita execução de código de terceiros, ele pode ser roubado.
A consequência prática:
- Mesmo domínio via proxy permite usar cookies protegidos sem complicação. É o arranjo mais seguro e o mais simples ao mesmo tempo.
- Subdomínios do mesmo domínio principal permitem cookies com configuração adequada, com algum cuidado.
- Domínios separados tornam o uso de cookies progressivamente mais difícil, empurrando para a segunda abordagem.
Este é o argumento mais forte a favor do arranjo de mesmo domínio: ele não é apenas mais simples de configurar — ele permite a estratégia de autenticação mais segura.
Erros comuns e o que eles significam
| Situação | Causa provável |
|---|---|
| Erro aparece só no navegador | Comportamento esperado da política de origem |
| Funciona em desenvolvimento, falha em produção | Origem de produção não declarada |
| Chamadas simples passam, outras não | Falta permissão para o método ou cabeçalho usado |
| Cookie não é enviado | Falta configuração específica para credenciais |
| Erro após adicionar um cabeçalho | Cabeçalho não está na lista de permitidos |
| Falha intermitente | Origens declaradas de forma inconsistente |
A terceira linha explica um comportamento que confunde: algumas chamadas passam sem qualquer configuração e outras não. Requisições consideradas simples pelo navegador são enviadas diretamente; as demais são precedidas de uma verificação de permissão, e é nessa verificação que a maior parte dos erros aparece.
A quarta merece nota: permitir a origem não basta para que cookies sejam enviados — existe uma configuração adicional específica para isso, tanto do lado do servidor quanto na chamada feita pelo front-end. É a causa mais comum de “a chamada passa mas o usuário aparece como não autenticado”.
O que não fazer
Três atalhos que resolvem o sintoma e criam problemas:
Permitir qualquer origem. É a solução que aparece primeiro em qualquer busca e a mais perigosa: ela autoriza qualquer site a fazer chamadas à sua API e ler as respostas. Em uma API pública sem dados sensíveis, pode ser aceitável. Em uma API com autenticação, não é.
Desativar a proteção no navegador durante o desenvolvimento. Resolve localmente e esconde o problema até a publicação — quando ele reaparece em produção, com pressa.
Usar um serviço externo que repassa as chamadas. Além de adicionar um intermediário desnecessário, significa enviar o tráfego da sua aplicação por terceiros.
A alternativa correta em desenvolvimento é usar o recurso de encaminhamento que as ferramentas de build oferecem, que simula o arranjo de mesma origem localmente — o que tem a vantagem adicional de aproximar o ambiente de desenvolvimento do de produção.
O que configurar no servidor
Quando a separação de origens for a escolha, os pontos de atenção:
- Declare origens específicas, e não qualquer uma.
- Liste os métodos que a API efetivamente usa.
- Liste os cabeçalhos que as chamadas enviam, incluindo os de autenticação.
- Habilite o envio de credenciais explicitamente, se usar cookies.
- Responda corretamente à verificação prévia, que o navegador envia antes das chamadas não simples.
- Defina um tempo de cache para essa verificação, evitando uma requisição extra a cada chamada.
- Trate ambientes separadamente, com as origens de desenvolvimento, homologação e produção declaradas conforme o caso.
O item 6 tem impacto de desempenho perceptível: sem ele, cada chamada não simples vira duas requisições — a verificação e a chamada em si. Em uma interface com muitas chamadas, isso dobra o número de idas ao servidor.
E o item 7 merece disciplina: declarar a origem de desenvolvimento em produção é um descuido comum e desnecessário.
Onde isso se encaixa na arquitetura
Vale situar a decisão no conjunto.
Se o seu front-end é servido como arquivos estáticos e a API é uma aplicação separada, o proxy reverso na frente resolve dois problemas de uma vez: elimina a questão de origens e centraliza o ponto de entrada, com HTTPS, compressão e controle de acesso em um lugar só.
Essa é a mesma peça de infraestrutura tratada nos artigos sobre aplicações Node.js em produção e sobre onde hospedar uma aplicação React — e é um dos motivos pelos quais aplicações com front-end e back-end separados pedem um ambiente com controle sobre a configuração do servidor.
Conclusão
O erro de origem cruzada não é um defeito a contornar: é uma proteção do navegador funcionando. A pergunta certa não é como desativá-la, e sim como organizar os endereços da aplicação.
A resposta mais simples resolve o problema pela raiz: servir front-end e API no mesmo domínio, em caminhos diferentes, com um proxy reverso encaminhando internamente. Sem origens distintas, não há o que configurar — e, como bônus, é o arranjo que permite a estratégia de autenticação mais segura.
Se a separação for necessária, declare origens específicas em vez de permitir qualquer uma, e lembre que habilitar o envio de cookies exige configuração própria além da permissão de origem. Conheça o Cloud Server para React da TBF Host e avalie o ambiente adequado à arquitetura do seu projeto.
Perguntas frequentes
O que é o erro de CORS?
É o navegador bloqueando a leitura de uma resposta vinda de uma origem diferente da página. Origem é a combinação de protocolo, domínio e porta — qualquer diferença cria origens distintas. O servidor de destino precisa declarar quais origens têm permissão para ler suas respostas.
Por que a chamada funciona em outra ferramenta e falha no navegador?
Porque a política de mesma origem é aplicada pelo navegador, não pelo servidor. A requisição chega e é respondida normalmente; o navegador é que impede a página de ler a resposta. Ferramentas de linha de comando ou clientes de API não aplicam essa regra.
Como evitar o problema de CORS de vez?
Servindo o front-end e a API no mesmo domínio, em caminhos diferentes, com um proxy reverso encaminhando internamente. Sem origens distintas, não há nada a configurar — e esse arranjo ainda permite usar cookies protegidos, que é a estratégia de autenticação mais segura.
Subdomínio conta como mesma origem?
Não. Origem é protocolo, domínio e porta exatos, então um subdomínio é uma origem diferente do domínio principal. Isso exige configuração de origens permitidas — embora subdomínios do mesmo domínio principal tenham mais opções para cookies que domínios totalmente distintos.
Por que algumas chamadas passam e outras não?
Porque requisições consideradas simples pelo navegador são enviadas diretamente, enquanto as demais são precedidas de uma verificação de permissão. A maior parte dos erros aparece nessa verificação — normalmente por falta de autorização para o método ou para algum cabeçalho enviado.
A chamada passa mas o usuário aparece como não autenticado. Por quê?
Provavelmente falta a configuração específica para envio de credenciais. Permitir a origem não basta: é preciso habilitar explicitamente o envio de cookies, tanto no servidor quanto na chamada feita pelo front-end. É a causa mais comum desse sintoma.
Posso permitir qualquer origem na minha API?
Em uma API pública sem dados sensíveis nem autenticação, pode ser aceitável. Em uma API autenticada, não — isso autoriza qualquer site a fazer chamadas e ler as respostas. É a solução que aparece primeiro em qualquer busca e a mais perigosa.
Como resolver o erro durante o desenvolvimento?
Usando o recurso de encaminhamento que as ferramentas de build oferecem, que simula o arranjo de mesma origem localmente. Desativar a proteção no navegador resolve só na sua máquina e esconde o problema até a publicação, quando ele reaparece com pressa.