Se você já viu a mensagem Access to fetch at '...' has been blocked by CORS policy no console do navegador, conhece bem essa frustração. Os erros de CORS estão entre os problemas mais comuns enfrentados por desenvolvedores web, mas o mecanismo por trás deles costuma ser mal compreendido. Este guia explica o CORS a partir dos fundamentos, para que você consiga corrigir esses erros — e entender por que eles existem.

O que é a Same-Origin Policy?

Os navegadores aplicam uma regra de segurança chamada Same-Origin Policy (SOP), ou política de mesma origem. Duas URLs têm a mesma origem quando compartilham o mesmo protocolo, o mesmo nome de host e a mesma porta.

Comparação de Origens
https://example.com/page1  →  https://example.com/page2     ✅ Mesma origem
https://example.com        →  http://example.com             ❌ Protocolo diferente
https://example.com        →  https://api.example.com        ❌ Nome de host diferente
https://example.com        →  https://example.com:8080       ❌ Porta diferente

A SOP impede que um site malicioso leia dados de outro site. Sem ela, qualquer página da web poderia fazer requisições à API do seu banco usando os seus cookies.

O que é CORS?

CORS (Cross-Origin Resource Sharing, ou Compartilhamento de Recursos entre Origens) é um mecanismo que flexibiliza a Same-Origin Policy. Ele permite que um servidor declare explicitamente quais outras origens podem acessar seus recursos. O servidor comunica isso por meio de cabeçalhos HTTP na resposta.

Como o CORS Funciona

Requisições Simples

Para requisições GET/POST simples com cabeçalhos padrão, o navegador envia a requisição diretamente e verifica os cabeçalhos da resposta:

Requisição CORS Simples
// O navegador envia:
GET /api/data HTTP/1.1
Host: api.example.com
Origin: https://myapp.com

// O servidor responde:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://myapp.com
Content-Type: application/json

{"data": "..."}

Requisições Preflight (OPTIONS)

Para requisições "não simples" (cabeçalhos personalizados, métodos PUT/DELETE, content type JSON), o navegador primeiro envia uma requisição preflight do tipo OPTIONS para pedir permissão ao servidor.

Requisição Preflight
// 1. O navegador envia o preflight:
OPTIONS /api/users HTTP/1.1
Host: api.example.com
Origin: https://myapp.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Content-Type, Authorization

// 2. O servidor responde com os métodos/cabeçalhos permitidos:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

// 3. O navegador envia a requisição real (somente se o preflight for aprovado)

Cabeçalhos CORS de Resposta

Cabeçalhos CORS Essenciais
Access-Control-Allow-Origin: https://myapp.com   // Quais origens podem acessar
Access-Control-Allow-Methods: GET, POST, PUT       // Métodos HTTP permitidos
Access-Control-Allow-Headers: Content-Type, Auth   // Cabeçalhos de requisição permitidos
Access-Control-Allow-Credentials: true             // Permite cookies/autenticação
Access-Control-Max-Age: 86400                      // Cache do preflight (segundos)
Access-Control-Expose-Headers: X-Request-Id        // Cabeçalhos legíveis pelo JS

Configuração do Servidor

Express.js (Node.js)
import cors from 'cors';

app.use(cors({
  origin: ['https://myapp.com', 'https://staging.myapp.com'],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400
}));
Nginx
location /api/ {
    add_header Access-Control-Allow-Origin "https://myapp.com" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE" always;
    add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;

    if ($request_method = OPTIONS) {
        return 204;
    }
}
PHP
header("Access-Control-Allow-Origin: https://myapp.com");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

Erros Comuns com CORS

  • Usar Access-Control-Allow-Origin: * com credenciais: O navegador vai bloquear essa combinação. Você precisa especificar a origem exata quando credentials: true.
  • CORS é um recurso de segurança do navegador: Ele NÃO protege sua API contra requisições de servidor para servidor. Sempre valide a autenticação em cada requisição.
  • Esquecer a flag always no Nginx: Sem ela, os cabeçalhos CORS não são enviados nas respostas de erro (4xx, 5xx).
  • Não tratar requisições OPTIONS: Se o seu servidor retornar 404 ou 405 para OPTIONS, todas as requisições preflight falham.

Experimente Nossas Ferramentas Gratuitas para Desenvolvedores

Codifique URLs, decodifique Base64 e formate JSON instantaneamente.