Guia completo para resolver o problema de não envio de cookies em pedidos Cross-Origin (CORS)
Se já se deparou com um cenário em que o servidor define o cookie corretamente (visível na resposta do navegador), mas nos pedidos seguintes o navegador não devolve esse cookie ao servidor, este guia é para si. Este problema ocorre quase sempre quando o frontend e o backend do seu projeto estão em dois domínios ou portas diferentes — por exemplo, frontend em app.example.com e API em api.example.com.
Porque é que isto acontece?
Os navegadores modernos impõem duas políticas de segurança rigorosas para prevenir ataques CSRF e sequestro de sessão:
- Política CORS: Por defeito, o navegador não permite que pedidos entre domínios incluam credenciais (como cookies), a menos que o servidor o permita explicitamente.
- Política SameSite: A partir do Chrome 80, os cookies são tratados por defeito com o comportamento
SameSite=Lax, o que significa que não serão enviados em pedidos entre domínios, a menos que sejam explicitamente definidos comSameSite=None.
O ponto importante é que, para resolver este problema, tanto o lado do cliente como o do servidor devem ser configurados corretamente. Modificar apenas um lado não é suficiente.
Passo 1: Configuração correta do servidor
Três regras de ouro no lado do servidor
Regra 1 — Ativar credenciais: O cabeçalho de resposta do servidor deve incluir o seguinte valor:
Access-Control-Allow-Credentials: true
Regra 2 — Sem curinga: Quando as credenciais estão ativadas, não pode usar o caractere curinga * no cabeçalho Access-Control-Allow-Origin. Deve especificar exatamente o endereço de domínio completo do frontend:
Access-Control-Allow-Origin: https://app.example.com
Regra 3 — Atributos do cookie: O cookie deve ser definido com dois atributos: SameSite=None e Secure. Sem estes dois atributos, o navegador armazenará o cookie, mas nunca o enviará em pedidos entre domínios.
Código de exemplo em Node.js (Express)
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: 'https://app.example.com', // Domínio exato do frontend, sem /
credentials: true
}));
app.post('/login', (req, res) => {
res.cookie('session_token', 'abc123', {
httpOnly: true, // Impede o acesso JavaScript ao cookie
secure: true, // Enviado apenas via HTTPS
sameSite: 'none', // Permite envio em pedidos Cross-Origin
maxAge: 24 * 60 * 60 * 1000
});
res.json({ message: 'Login bem-sucedido' });
});
Código de exemplo em PHP
<?php
// Especifique o domínio exato do frontend, não *
header("Access-Control-Allow-Origin: https://app.example.com");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
// Responder ao pedido Preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
// Definir o cookie com os atributos necessários
setcookie('session_token', 'abc123', [
'expires' => time() + 86400,
'path' => '/',
'secure' => true, // Obrigatório
'httponly' => true,
'samesite' => 'None' // Obrigatório para Cross-Origin
]);
Nota: Se estiver a usar Laravel, defina supports_credentials como true no ficheiro config/cors.php e adicione o domínio do frontend ao array allowed_origins.
Passo 2: Configuração correta do cliente (frontend)
Mesmo com a configuração completa do servidor, o navegador ainda não enviará cookies, a menos que declare explicitamente no lado do cliente que este pedido é "com credenciais".
Usando Fetch API
fetch('https://api.example.com/user/profile', {
method: 'GET',
credentials: 'include' // Esta linha é a chave para resolver o problema
})
.then(res => res.json())
.then(data => console.log(data));
Usando Axios
// Para um pedido específico
axios.get('https://api.example.com/user/profile', {
withCredentials: true
});
// Ou globalmente para todo o projeto
axios.defaults.withCredentials = true;
Lista de verificação para resolução de problemas
Se o problema persistir após aplicar o acima, verifique estes itens por ordem:
- ✅ Ambos os lados estão em HTTPS? O atributo
Securesignifica que o cookie só funciona em ligações encriptadas. Se o seu site estiver em HTTP, o navegador não aceitará o cookie. (Exceção: ambiente de desenvolvimento emlocalhost) - ✅ O endereço Origin é exato? O endereço
Access-Control-Allow-Origindeve corresponder exatamente ao URL que vê no navegador. Mesmo uma diferença emwwwou uma barra final/causará falha. - ✅ O pedido OPTIONS é bem-sucedido? No separador Network das ferramentas de desenvolvimento do navegador, verifique o pedido Preflight (com o método OPTIONS). Este pedido deve ser respondido com código 200 ou 204 e cabeçalhos CORS corretos.
- ✅ O cookie está armazenado? No navegador, vá para DevTools ← Application ← Cookies e certifique-se de que o cookie está armazenado com os atributos
SecureeSameSite=None. - ✅ Tem um proxy ou firewall intermédio? Por vezes, Cloudflare ou servidores web como Nginx reescrevem cabeçalhos. Verifique também a configuração deles.
Resumo
O envio de cookies em pedidos entre domínios requer a coordenação de três fatores: o servidor com Access-Control-Allow-Credentials: true e Origin exato, o cookie com atributos SameSite=None; Secure, e o cliente com ativação de credentials: 'include' ou withCredentials: true. Seguindo estes três pontos, o problema será completamente resolvido.
Infraestrutura confiável, tranquilidade para programadores
A implementação correta de CORS e a gestão de cookies é apenas parte da história; a infraestrutura em que o seu projeto é executado também desempenha um papel decisivo na estabilidade e segurança do serviço:
Radib Hosting — Alojamento web de alta velocidade com suporte completo para SSL gratuito e configuração padrão de cabeçalhos; uma escolha ideal para alojar o frontend e backend dos seus projetos.
Radib Virtual Server — Se o seu projeto requer acesso completo, recursos dedicados e liberdade na configuração do servidor web (Nginx/Apache), os servidores virtuais Radib com hardware poderoso e rede estável são a melhor escolha para APIs profissionais.
Radib Debugging and Security Services — Se está a lidar com erros complexos de CORS, problemas de autenticação ou desafios de segurança, a equipa técnica da Radib, com profunda experiência em resolução de problemas e segurança de aplicações web, está aqui para ajudá-lo a resolver o problema pela raiz.


