Como corrigir erros de CORS (e por que eles acontecem)
Um erro de CORS significa que a sua página web tentou ler uma resposta de uma origem diferente (outro domínio, porta ou protocolo), e esse servidor não enviou cabeçalhos dizendo que isso é permitido. Os navegadores bloqueiam a resposta para proteger o usuário. Você corrige isso no servidor, retornando um cabeçalho Access-Control-Allow-Origin para a origem do seu site e tratando requisições de preflight OPTIONS, ou evita o problema enviando a requisição pelo seu próprio backend, na mesma origem.
É um dos erros mais confusos do desenvolvimento web porque, muitas vezes, a requisição chega ao servidor sem problemas. Este guia explica o que está acontecendo e como corrigir cada variante.
O que significa “origem”
Uma origem é a combinação de protocolo, domínio e porta:
| URL | Origem |
|---|---|
https://meuapp.com/dashboard | https://meuapp.com |
https://api.meuapp.com/usuarios | https://api.meuapp.com (subdomínio diferente, portanto origem diferente) |
http://localhost:5173 | http://localhost:5173 |
http://localhost:3000 | http://localhost:3000 (porta diferente, portanto origem diferente) |
Os navegadores seguem a política de mesma origem: o JavaScript de uma página pode ler livremente as respostas da própria origem, mas não de outras. O CORS (Cross-Origin Resource Sharing) é o sistema que permite que um servidor opte por isso: “respostas minhas podem ser lidas por páginas dessas origens”.
Duas consequências surpreendem as pessoas:
- A requisição muitas vezes chega ao servidor. O CORS normalmente impede que o seu código leia a resposta, não que o servidor receba a requisição. Um POST pode ter sido salvo mesmo que você tenha visto um erro.
- Só os navegadores aplicam. curl, Postman e código do lado do servidor ignoram o CORS por completo. Por isso “funciona no Postman” não diz nada sobre CORS.
Passo 1: leia o erro exato
Abra as ferramentas de desenvolvedor (clique com o botão direito → Inspecionar), vá para o Console e leia a mensagem completa. A redação do Chrome indica qual é o problema:
| A mensagem contém | O que está errado |
|---|---|
No 'Access-Control-Allow-Origin' header is present | O servidor não enviou o cabeçalho, ou a requisição falhou antes de chegar ao seu código de CORS (por exemplo, um 404 ou 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | O servidor permite uma origem diferente da sua |
Response to preflight request doesn't pass access control check | A requisição preflight OPTIONS falhou |
...must not be the wildcard '*' when the request's credentials mode is 'include' | Você está enviando cookies, e o servidor respondeu com * |
Request header field authorization is not allowed | O servidor não listou esse cabeçalho em Access-Control-Allow-Headers |
Em seguida, abra a aba Rede, encontre a requisição que falhou (e qualquer requisição OPTIONS antes dela) e veja o código de status e os cabeçalhos da resposta.
Verifique primeiro o código de status. Muitos “erros de CORS” são, na verdade, um erro do servidor disfarçado. Se o servidor quebra ou retorna um 404, a resposta de erro dele muitas vezes não tem os cabeçalhos de CORS, então o navegador informa CORS em vez do problema real. Corrija o 500 ou o 404, e o erro de CORS pode desaparecer.
Passo 2: decida se o navegador deveria chamar essa API
Antes de adicionar cabeçalhos, pergunte: o navegador deveria chamar essa API diretamente?
- Uma API de terceiros que exige uma chave secreta (OpenAI, a chave secreta do Stripe, a maioria dos serviços de e-mail) nunca deve ser chamada pelo navegador. A chave ficaria visível para todos os visitantes. Chame-a a partir do seu backend, e o problema de CORS desaparece, porque requisições de servidor para servidor não estão sujeitas ao CORS. Veja como manter as chaves de API seguras.
- Uma API de terceiros que você não controla e que não envia cabeçalhos de CORS não pode ser corrigida do seu lado. Chame-a pelo seu backend.
- Sua própria API pode ser corrigida configurando-a corretamente. Continue abaixo.
Passo 3: corrija no seu servidor
O servidor precisa adicionar os cabeçalhos corretos às respostas, inclusive às respostas de erro.
Para a requisição real, envie:
Access-Control-Allow-Origin: https://meuapp.com(a origem exata do seu frontend, sem barra final)Vary: Origin, se o valor depender da origem que fez a requisição
Para a requisição preflight OPTIONS, responda com um status de sucesso (200 ou 204) e:
Access-Control-Allow-Origin: https://meuapp.comAccess-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETEAccess-Control-Allow-Headers: Content-Type, Authorization(cada cabeçalho personalizado que você envia)- Opcionalmente
Access-Control-Max-Age: 600, para que o navegador guarde o preflight em cache por um tempo
A maioria dos frameworks tem um pacote ou uma configuração que faz isso. No Express, o pacote cors; no FastAPI, CORSMiddleware; no ASP.NET Core, AddCors; no Spring, @CrossOrigin ou uma configuração de CORS. Uma configuração típica no Express:
import cors from "cors";
app.use(cors({
origin: ["https://meuapp.com", "http://localhost:5173"],
credentials: true,
}));
Coloque o tratamento de CORS antes das suas rotas e da autenticação, para que as requisições preflight (que não levam login) não sejam rejeitadas com um 401.
Com um criador com IA, descreva a configuração com precisão:
O frontend em
https://meuapp.comchama a API emhttps://api.meuapp.come recebe "Response to preflight request doesn't pass access control check". Configure o CORS na API para permitir exatamentehttps://meuapp.come a origem da prévia, permitir GET, POST, PATCH, DELETE com os cabeçalhos Content-Type e Authorization, tratar OPTIONS antes da autenticação e incluir os cabeçalhos de CORS também nas respostas de erro.
Passo 4: trate cookies e credenciais
Se o seu frontend envia cookies (por exemplo, uma sessão de login) para outra origem, os dois lados precisam estar de acordo:
- O frontend define
credentials: "include"nofetch, ouwithCredentials: trueno axios. - O servidor envia
Access-Control-Allow-Credentials: true. - O
Access-Control-Allow-Origindo servidor precisa ser a origem exata, não*.
Cookies entre sites também precisam de SameSite=None; Secure, e alguns navegadores restringem ainda mais os cookies de terceiros. Isso é mais um motivo para preferir a abordagem do Passo 5.
Passo 5: evite o CORS com uma configuração de mesma origem
Muitas vezes, a correção mais limpa é não fazer requisições entre origens. Sirva a API a partir da mesma origem da página, por exemplo em https://meuapp.com/api/...:
- Em desenvolvimento, a maioria dos servidores de desenvolvimento consegue fazer proxy. A opção
server.proxydo Vite pode encaminhar/apipara o seu backend em outra porta, então o navegador só fala com uma origem. - Em produção, direcione
/apipara o backend pelas configurações de rewrite ou proxy da sua hospedagem, ou sirva o frontend e a API a partir de um único servidor.
O frontend passa a chamar um caminho relativo como fetch("/api/pedidos"). Não há requisição entre origens, nenhum preflight entre origens e nenhuma dor de cabeça com cookies. Também significa que você não precisa fixar um domínio de API que muda entre a prévia e a produção.
Altere o frontend para chamar o backend com caminhos relativos /api em vez de uma URL completa, e configure um proxy de desenvolvimento para que /api seja encaminhado ao servidor da API. Depois, remova as configurações de CORS que não são mais necessárias.
O que não fazer
mode: "no-cors"nofetch. Não contorna nada; entrega ao seu código uma resposta vazia e ilegível.- Extensões do navegador que desativam o CORS. Elas mudam apenas o seu navegador. Todos os visitantes continuam vendo o erro.
- Serviços públicos de “proxy CORS” para apps reais. Eles podem ler e alterar tudo o que passa por eles, e às vezes saem do ar.
Access-Control-Allow-Origin: *em uma API que usa login. Não funciona com credenciais de qualquer forma, e é o padrão errado para dados privados.- Refletir qualquer cabeçalho
Originde volta com credenciais permitidas. Isso permite que qualquer site faça requisições autenticadas em nome dos seus usuários. Use uma lista de permitidos.
Causas comuns em apps criados com IA
| Situação | Correção |
|---|---|
| O frontend chama uma API de terceiros com uma chave secreta | Mova a chamada para o backend |
| Funciona na prévia, falha no domínio publicado | Adicione as origens publicada e de domínio personalizado à lista de permitidos, ou use caminhos relativos /api |
| Erro apenas em POST, PUT ou DELETE | Preflight não tratado; adicione o tratamento de OPTIONS e os cabeçalhos permitidos |
| O erro apareceu depois de adicionar login | Credenciais exigem uma origem exata e Allow-Credentials |
| “Erro de CORS”, mas a aba Rede mostra 500 | Corrija primeiro o erro do servidor |
URL da API fixada em localhost | Use caminhos relativos ou uma configuração por ambiente |
CORS na Mythex
Quando um projeto da Mythex tem um site e um servidor de API, ambos rodam como serviços no mesmo projeto, e você pode alternar entre eles na prévia. Pedir ao agente que o frontend chame o backend por um caminho relativo /api, com proxy em desenvolvimento, evita a maioria dos problemas de CORS. Se você realmente precisar de chamadas entre origens, passe ao agente o erro exato do console e as origens envolvidas. Verifique o resultado também no app publicado, já que o endereço dele é diferente da prévia. Veja Apps com vários serviços e Backends de API na documentação, e nossos guias sobre como depurar um app criado com IA e frontend versus backend.
Checklist de CORS
- Li o erro completo do console e o código de status da requisição que falhou
- Descartei um 404 ou 500 escondido
- APIs com chave secreta são chamadas pelo backend, não pelo navegador
- O servidor envia
Access-Control-Allow-Origincom as origens exatas permitidas - O preflight
OPTIONSé respondido com os métodos e cabeçalhos permitidos, antes da autenticação - Os cabeçalhos de CORS também estão presentes nas respostas de erro
- Credenciais: origem exata,
Allow-Credentials: truee configurações corretas de cookie - Origens de prévia, publicada e de domínio personalizado cobertas, ou caminhos relativos
/apiusados - Nenhum atalho de
no-cors, proxy público ou reflexão de qualquer origem
Perguntas
O que significa um erro de CORS?
Sua página, carregada de uma origem, tentou ler uma resposta de uma origem diferente, e o servidor dessa origem não incluiu cabeçalhos que permitam isso. O navegador impede que o seu código leia a resposta. A correção está no servidor, ou em como a requisição é roteada, e não no código do frontend.
Posso corrigir um erro de CORS pelo frontend?
Não de forma adequada. Configurações como mode: 'no-cors' apenas escondem a resposta do seu código. Você corrige fazendo o servidor enviar o cabeçalho Access-Control-Allow-Origin correto, ou chamando a API a partir do seu próprio backend ou de um proxy da mesma origem.
Access-Control-Allow-Origin: * é seguro?
É aceitável para dados públicos que qualquer pessoa pode ler, como uma API pública sem login. Não pode ser usado com cookies ou outras credenciais, e para APIs privadas você deve listar as origens exatas que são permitidas.
Por que minha requisição funciona no Postman ou no curl, mas não no navegador?
O CORS é aplicado apenas pelos navegadores. Ferramentas como Postman e curl não o aplicam, então uma requisição pode dar certo ali e ainda ser bloqueada quando o JavaScript da página a faz.
O que é uma requisição de preflight?
Para requisições que não são simples, como um POST com JSON ou uma com cabeçalho Authorization, o navegador primeiro envia uma requisição OPTIONS perguntando ao servidor quais métodos e cabeçalhos são permitidos. Se essa requisição OPTIONS falhar ou não tiver os cabeçalhos certos, a requisição real nunca é enviada.