Configurações de cookies SameSite: Secure, escopo de domínio e subdomínios
Configurações SameSite explicadas: corrija Secure, HttpOnly, escopo de domínio e comportamento em subdomínios para que logins funcionem de forma confiável em produção.

Por que a autenticação quebra em produção quando os cookies estão mal configurados
Quando o login funciona no localhost, mas falha no seu domínio real, o problema frequentemente não é a verificação de senha ou o banco de dados. É o cookie.
O teste local é permissivo: tudo roda no mesmo host, você pode estar em HTTP simples, e os redirecionamentos são mais simples. Em produção, os navegadores aplicam regras mais rígidas. Detalhes pequenos de cookie decidem se o navegador vai enviar sua sessão de volta ao servidor.
Os sintomas podem parecer não relacionados:
- o formulário de login é enviado, mas você volta para a página de login
- um loop de redirecionamento entre
/logine/app - sessões que desaparecem depois de um refresh
- um navegador funciona enquanto outro falha
Ambientes de produção adicionam partes móveis: HTTPS, CDNs ou proxies, subdomínios separados (como app.example.com e api.example.com) e redirecionamentos por terceiros (OAuth, páginas de pagamento, links mágicos por e-mail). É aí que SameSite, Secure e o escopo do cookie começam a importar.
Um cookie não é apenas "um token de sessão." É também um conjunto de regras que diz ao navegador quando enviar esse token.
A má configuração costuma quebrar a autenticação de algumas maneiras previsíveis:
- O navegador nunca envia o cookie na requisição que cria ou verifica a sessão (frequentemente SameSite ou escopo de domínio).
- O navegador rejeita o cookie porque
Securenão está definido quando deveria. - O cookie está com o
DomainouPatherrado, então não alcança as rotas que precisam dele. - Existem dois cookies com o mesmo nome (antigo e novo, staging e prod), e o navegador envia um diferente do que você espera.
Exemplo: tudo funciona em http://localhost:3000, mas depois do deploy para app.yourdomain.com, sua API define um cookie de sessão apenas para host api.yourdomain.com. Seu frontend nunca o envia, então cada carregamento de página parece deslogado.
Noções básicas de cookie que importam para autenticação
A maioria das experiências de “login” ainda depende de um cookie que representa sua sessão. Depois de digitar a senha, o servidor envia um cookie na resposta e o navegador o armazena. Em requisições futuras, o navegador anexa automaticamente esse cookie para que o servidor possa reconhecê-lo.
Muita confusão vem de misturar três ideias relacionadas:
- Cookie de sessão: um identificador que o servidor consulta (frequentemente armazenado em banco ou cache).
- Access token: uma credencial de vida curta (muito usada em APIs).
- Refresh token: uma credencial mais duradoura usada para obter um novo access token.
Bugs de autenticação em produção frequentemente aparecem quando um app espera uma abordagem, mas implementa outra. Por exemplo, o frontend espera sessão baseada em cookie, mas o backend emite tokens pensados para o cabeçalho Authorization.
Para autenticação baseada em cookie, os atributos importam tanto quanto o valor:
- SameSite: controla quando cookies são enviados em contextos cross-site.
- Secure: o cookie só é enviado via HTTPS.
- HttpOnly: impede que JavaScript leia o cookie.
- Domain: quais nomes de host podem recebê-lo.
- Path: quais caminhos da URL podem recebê-lo.
Os navegadores nem sempre enviam cookies. Eles só os enviam quando domínio e caminho batem, a conexão satisfaz Secure, e o contexto da requisição passa nas regras do SameSite.
Uma falha clássica exclusiva de produção: localmente tudo é localhost, mas em produção o frontend está em https://app.example.com e a API em https://api.example.com. Se Domain ou SameSite estiverem mesmo que seja um pouco errados, você terá um loop de login.
SameSite: o que faz e quando bloqueia seu login
SameSite é uma flag de cookie que diz ao navegador quando ele tem permissão para enviar seu cookie de sessão. Muitos problemas de “funciona local, quebra em produção” vêm de configurações de SameSite que não combinam com o fluxo real de login.
Lax vs Strict vs None (em termos simples)
SameSite=Strict é o mais restrito. O cookie é enviado apenas em contexto first-party. Se o usuário chegar vindo de outro site, o navegador pode reter o cookie.
SameSite=Lax é o padrão que funciona para muitos apps. O cookie normalmente é enviado em navegações top-level normais (como clicar num link), mas não na maioria das requisições cross-site em segundo plano.
SameSite=None significa “permitir este cookie em contextos cross-site.” Navegadores modernos exigem Secure quando você usa None, ou vão descartar o cookie.
O que costuma disparar a quebra
SameSite muito restrito frequentemente quebra:
- logins OAuth (Google, GitHub) onde o usuário é redirecionado de volta
- apps incorporados (seu app dentro de um iframe em outro domínio)
- fluxos onde o navegador classifica frontend e API como cross-site
Os padrões dos navegadores também mudaram com o tempo. Cookies sem um SameSite explícito podem ser tratados como Lax, e cookies definidos como None sem Secure são comumente rejeitados.
Quando você realmente precisa de SameSite=None? Use-o somente quando o cookie de sessão tiver que ser enviado em um contexto cross-site (iframes, setups verdadeiramente cross-site, alguns fluxos baseados em redirecionamento). Se tudo for same-site, Lax normalmente é suficiente e reduz risco.
Cookies Secure e HTTPS: o desalinho mais comum em produção
Um cookie marcado Secure só é enviado sobre HTTPS. Isso parece simples, mas é uma das principais razões pelas quais logins funcionam localmente e falham depois do deploy.
Uma regra pega as pessoas desprevenidas: se você usa SameSite=None, navegadores modernos exigem que o cookie também seja Secure. Sem isso, o navegador pode descartar o cookie silenciosamente.
O desenvolvimento local engana times. Muitos apps rodam em http://localhost, então Secure é ignorado para facilitar testes. Depois, em produção, roda em HTTPS, alguém ajusta para SameSite=None por conta de um redirect ou embed, e o cookie nunca persiste.
Proxies e CDNs podem agravar isso. Seu navegador está em HTTPS, mas seu servidor de aplicação pode ver a requisição como HTTP porque o TLS termina no proxy. Se a app concluir “estou em HTTP”, ela pode se recusar a definir Secure, ou gerar redirecionamentos que alternam entre HTTP e HTTPS.
Se cookies somem só no site ao vivo, verifique:
- Nas DevTools, confirme que o cookie de autenticação mostra
Securee que a URL da requisição éhttps://... - Procure avisos como “cookie was blocked because it had SameSite=None without Secure”
- Verifique cabeçalhos de proxy (frequentemente
X-Forwarded-Proto: https) e se seu framework está configurado para confiar no proxy - Garanta que usuários não consigam acessar uma versão HTTP do site
- Confirme que o cookie é definido no domínio final após redirecionamentos, não num hostname intermediário
HttpOnly e CSRF: mantenha o cookie mais seguro sem quebrar UX
Se seu cookie de sessão for legível em JavaScript, qualquer bug de XSS pode se transformar em tomada de conta de conta. Por isso HttpOnly importa. Com HttpOnly, o navegador ainda envia o cookie nas requisições, mas document.cookie não consegue lê-lo.
Armazenar autenticação em um cookie legível por JS costuma ser conveniente para uma SPA, mas geralmente aumenta o risco sem benefício real. Se o frontend precisa saber se o usuário está autenticado, chame um endpoint leve como /me e deixe o servidor decidir com base no cookie.
CSRF é a outra metade dessa história. Cookies são enviados automaticamente, então um site malicioso pode tentar disparar requisições a partir do navegador do usuário autenticado. SameSite ajuda, mas requisições que mudam estado ainda precisam de proteção CSRF.
Regras práticas que mantêm a UX simples enquanto aumentam a segurança:
- Mantenha o token de sessão apenas em um cookie
HttpOnly(não no localStorage). - Use proteção CSRF para requisições que mudam estado.
- Escopo os cookies de forma restrita (host e path) para que menos requisições carreguem sua sessão.
Uma troca a considerar: se você usa cookies para autenticação de API, sua SPA não pode anexá-los manualmente. Dependem do navegador, então CORS e configurações de credentials precisam estar corretas.
Escopo de Domain e Path: pare cookies de irem para o lugar errado
Bugs de cookie frequentemente aparecem como “deslogouts aleatórios” ou “funciona local, mas não depois do deploy.” Domain e Path decidem onde o navegador enviará seu cookie de autenticação. Se não baterem com suas URLs reais, seu servidor nunca vê o cookie e trata o usuário como deslogado.
Mesmo SameSite perfeito não ajuda se o cookie não for enviado.
Cookies host-only vs Domain
Se você não define o atributo Domain, o cookie é host-only. Ele fica preso ao host exato que o definiu, como app.example.com.
Se você define Domain=.example.com, o cookie fica disponível para subdomínios como app.example.com e api.example.com. Isso pode ser útil, mas também amplia onde o cookie pode ser enviado e aumenta a chance de um subdomínio sobrescrever outro cookie com o mesmo nome.
Path em setups com múltiplas apps
Path é a “pasta” da URL onde o cookie é válido. Path=/ envia o cookie para todo caminho naquele host. Path=/app envia apenas para /app e abaixo.
Um erro comum é definir o cookie com Path=/api porque ele foi criado numa rota de API, e depois se perguntar por que páginas em /app não permanecem logadas.
Checagens rápidas que previnem muitos problemas de autenticação só em produção:
- Escolha um host canônico (
wwwou semwww) e mantenha-o. - Se precisar de autenticação compartilhada entre subdomínios, use um cookie no domínio pai. Caso contrário, deixe
Domainsem valor. - Use
Path=/a menos que haja motivo claro para isolar cookies. - Evite reutilizar o mesmo nome de cookie entre apps diferentes com escopos diferentes.
- Verifique qual host realmente define o cookie após redirecionamentos.
Subdomínios: comportamento previsível entre app e API
Um setup comum é app.example.com para o frontend e api.example.com para o backend. Parece simples, mas regras de cookie podem se alterar entre o dev local e a produção quando HTTPS, proxies e domínios reais entram em cena.
Se um cookie for host-only, um cookie definido por api.example.com não será enviado para app.example.com, e vice-versa. Se você realmente precisa que um cookie funcione em ambos, normalmente é preciso escopá-lo para o domínio pai.
Antes de compartilhar cookies entre subdomínios, confirme:
- Você realmente precisa do mesmo cookie em ambos os subdomínios, ou a API pode ser o único lugar que o define e lê?
- Está usando HTTPS de ponta a ponta, inclusive atrás de load balancer ou CDN?
- Suas configurações SameSite batem com a forma que o navegador classifica suas requisições (same-site vs cross-site)?
Lembre-se também: CORS e cookies devem combinar. Mesmo que o cookie esteja com escopo correto, o navegador não o anexará a requisições de API a menos que seu fetch/XHR use credentials, e a API permita credentials com uma origem explícita.
Compartilhar cookies entre subdomínios nem sempre vale a pena. Um cookie de domínio amplo aumenta onde ele pode ser enviado. Mantenha cookies de autenticação o mais restritos possível e aumente o escopo apenas quando houver necessidade clara.
Passo a passo: uma configuração segura de cookies para navegadores modernos
Uma configuração segura de cookie começa com a jornada real do usuário, não com uma configuração padrão de framework. O que funciona no localhost pode falhar depois do deploy porque produção adiciona HTTPS, redirecionamentos e hosts separados.
Lista prática de verificação
Mapeie seu fluxo de login de ponta a ponta e faça o cookie corresponder a ele:
- Mapeie o fluxo real de login (incluindo redirecionamentos). Anote cada etapa: app, provedor de auth, URL de callback, dashboard.
- Decida onde a sessão deve viver. Escolha um lugar para definir e ler o cookie de sessão de forma consistente (frequentemente a API).
- Escolha SameSite baseado nesse fluxo. Use
Nonesomente se precisar enviar cookies em contextos cross-site. Caso contrário,Laxcostuma bastar. - Aplique HTTPS e defina
SecureeHttpOnly. Se usarSameSite=None, você deve usarSecure. - Defina
DomainePathintencionalmente. Amplie o escopo só quando necessário. MantenhaPath=/a menos que haja motivo para limitar.
Valide no domínio real de produção em uma janela anônima: faça login, hard refresh, abra uma nova aba e confirme que o cookie está presente e é enviado nas requisições que importam.
Erros comuns que causam bugs de autenticação difíceis de depurar
Bugs de cookie parecem aleatórios porque geralmente aparecem só após o deploy. Pequenas diferenças (HTTPS, um domínio real, um proxy, um host de API separado) fazem as regras do navegador importarem.
Os erros por trás da maioria dos loops de login e relatos de “deslogado após refresh”:
- Definir
SameSite=Nonemas esquecerSecure(o navegador pode descartar o cookie). - Tornar
Domainamplo demais e compartilhar cookies involuntariamente com outros subdomínios. - Misturar HTTP e HTTPS atrás de um proxy, fazendo a app definir cookies ou redirecionamentos com base no esquema errado.
- Confiar no comportamento do localhost, que não bate com domínios reais.
- Tratar CORS como o único problema. CORS pode permitir a requisição, mas cookies ainda podem ser bloqueados por escopo ou SameSite.
Exemplo: você faz deploy de app.example.com (frontend) e api.example.com (backend). Atualiza SameSite para permitir comportamento cross-site, mas esquece Secure. Em produção, o navegador descarta o cookie de sessão e cada refresh parece um usuário novo.
Verificações rápidas antes de enviar (e quando receber um bug)
A maioria dos bugs de cookie fica óbvia quando você checa três lugares: o armazenamento de cookies do navegador, a requisição de rede e a razão do servidor para rejeitar a sessão.
Nas DevTools (Application/Storage), clique no cookie e verifique:
- O cookie está presente após o login e persiste depois do refresh?
SameSite,Secure,HttpOnly,DomainePathestão como você espera?ExpiresouMax-Ageparecem razoáveis?- Você não está definindo dois cookies com o mesmo nome em domínios diferentes por acidente?
- O cookie está sendo definido pelo host que você pensa (app vs api)?
Depois, verifique a aba Network. Inspecione uma requisição autenticada (como GET /me). Se o cookie existe no armazenamento mas não aparece na requisição, ou os atributos estão bloqueando, ou a requisição vai para um host diferente do que você imagina.
Por fim, verifique HTTPS de ponta a ponta. Se o TLS termina num load balancer mas faltam cabeçalhos de proxy, a app pode definir cookies não-Secure ou gerar redirecionamentos que quebram a sessão.
Quando possível, registre no servidor uma razão clara para rejeição de sessão: cookie ausente, sessão expirada, assinatura inválida, falha CSRF etc.
Exemplo: loop de login após deploy devido a SameSite e domínio
Uma história comum: OAuth funciona no localhost, depois quebra quando você faz deploy em https://app.example.com. Usuários clicam em “Continue with Google”, são redirecionados de volta, parecem brevemente logados e então voltam para a página de login. Repetidamente.
O que geralmente acontece é um descompasso de cookies durante o redirecionamento OAuth e entre subdomínios.
Localmente, seu app e API podem estar ambos em localhost, então o navegador envia o cookie para todo lado. Após o deploy, o fluxo costuma ser assim:
-
O provedor OAuth redireciona o usuário para
https://app.example.com/auth/callback. -
O callback define um cookie de sessão, mas ele é host-only para
app.example.com(sem o atributoDomain). -
O frontend chama
https://api.example.com/mepara buscar o usuário logado. -
O navegador não envia o cookie para
api.example.com, então a API retorna 401. A app interpreta como “não autenticado” e reinicia o fluxo de login.
SameSite pode piorar. Se o cookie usado durante o callback OAuth for SameSite=Strict, o navegador pode não enviá-lo no redirecionamento cross-site de volta do provedor, então seu servidor não consegue casar o state e o fluxo falha.
Um plano de correção prático:
- Defina
Secure=trueem produção (especialmente se usarSameSite=None). - Use
SameSite=Laxpara sessões típicas e cookies de state do OAuth (normalmente sobrevive a redirecionamentos top-level). - Se a API realmente precisa do mesmo cookie, escopá-lo para o domínio pai e manter o
Pathconsistente.
Para confirmar a correção sem chutar no escuro:
- Verifique a entrada do cookie para
Domain,Path,SameSiteeSecure. - Na requisição de API que falha, confirme se o cabeçalho
Cookieestá presente. - Procure notas de “blocked” no painel de cookies (os navegadores geralmente explicam por que um cookie foi rejeitado).
Próximos passos: consolide e peça ajuda se ainda estiver instável
Depois de encontrar uma configuração de cookie que funciona, documente-a como regra, não como palpite: os valores exatos para SameSite, Secure, HttpOnly, Domain e Path, e o que muda entre local, staging e produção.
Mantenha um plano de testes pequeno que você repita antes dos releases: login, refresh, nova aba, janela anônima e um segundo navegador (Chrome e Safari normalmente revelam diferenças rapidamente).
Se você está lidando com um protótipo gerado por IA que quebra ao ir para domínios reais, normalmente é um dos poucos culpados recorrentes: falta de Secure, Domain/Path desencontrados, cookies definidos no host errado após redirecionamentos ou comportamento cross-site que o navegador bloqueia.
Se quiser uma segunda opinião, FixMyMess (fixmymess.ai) foca em pegar apps gerados por IA quebrados e torná-los prontos para produção, incluindo diagnosticar fluxos de cookie e autenticação de ponta a ponta. Uma auditoria rápida costuma ser suficiente para apontar o atributo ou etapa de redirecionamento que quebra a sessão.
Perguntas Frequentes
Por que o login funciona no localhost, mas falha depois do deploy?
Normalmente o navegador não está enviando de volta o cookie de sessão no seu domínio de produção. No localhost tudo compartilha o mesmo host, mas em produção HTTPS, subdomínios e redirecionamentos ativam regras mais rígidas, de modo que um SameSite, Secure, Domain ou Path ligeiramente errados podem fazer o servidor acreditar que você não está autenticado.
O que causa o loop “/login” ↔ “/app”?
Um loop de redirecionamento normalmente significa que a aplicação define um cookie durante o login, mas a próxima requisição que verifica a sessão não inclui esse cookie. As causas mais comuns são um cookie com escopo errado (host do app vs subdomínio da API), SameSite bloqueando durante um fluxo baseado em redirecionamento, ou o cookie sendo descartado por usar SameSite=None sem Secure.
Qual configuração SameSite devo usar para a maioria dos cookies de autenticação?
Comece com SameSite=Lax para uma sessão típica de login web, pois geralmente sobrevive a navegações top-level e muitos redirecionamentos OAuth. Use SameSite=None somente quando você realmente precisa enviar cookies em contextos cross-site (como iframes ou setups verdadeiramente cross-site), e sempre com Secure habilitado.
Por que `SameSite=None` exige `Secure`?
Navegadores modernos rejeitam cookies com SameSite=None a menos que também tenham Secure, ou seja, só sejam enviados sobre HTTPS. Se você esquecer Secure, o cookie pode parecer ter sido criado pelo servidor, mas o navegador o descarta silenciosamente, fazendo com que cada refresh pareça um usuário deslogado.
Por que cookies Secure quebram atrás de um CDN ou reverse proxy?
Secure significa que o cookie só é enviado via HTTPS. Em produção isso é o desejado, mas proxies podem confundir sua aplicação fazendo-a acreditar que a requisição chegou por HTTP, o que muda como cookies e redirecionamentos são gerados. A correção costuma ser forçar HTTPS e garantir que o backend confie nos cabeçalhos do proxy para saber que o esquema original era HTTPS.
Qual a diferença entre um cookie host-only e um cookie de Domain?
Um cookie host-only (sem o atributo Domain) é enviado apenas ao host exato que o definiu, como api.example.com. Um cookie de domínio (por exemplo .example.com) pode ser enviado para vários subdomínios. Se seu frontend está em app.example.com e o cookie for host-only em api.example.com, o frontend não o envia nas requisições a app.example.com, o que costuma causar o comportamento “deslogado após refresh”.
Como o Path do cookie pode fazer eu “perder” minha sessão aleatoriamente?
O atributo Path restringe onde o cookie é enviado no mesmo host. Se você acidentalmente definiu Path=/api, então páginas em /app não receberão o cookie mesmo estando no mesmo domínio, e as verificações de sessão falham. Para a maioria dos cookies de autenticação, Path=/ é o padrão mais simples, a menos que haja um motivo claro para isolar.
Meu cookie de sessão deve ser HttpOnly, e isso vai quebrar minha SPA?
Use HttpOnly para que o JavaScript não consiga ler o cookie de sessão, o que reduz o dano de um XSS. Se seu frontend precisa saber se o usuário está logado, consulte um endpoint no servidor (como who am I) em vez de ler um token no navegador. Isso mantém o estado de login preciso sem expor segredos ao código do cliente.
Como eu depuro rapidamente se o cookie está sendo setado e enviado?
Primeiro, verifique se o cookie existe no navegador após o login e se persiste depois de um hard refresh. Em seguida, inspecione uma requisição autenticada na aba Network e confirme se o cabeçalho Cookie está presente. Se o cookie está armazenado mas não é enviado, quase sempre é problema de SameSite, Secure, Domain, Path ou a requisição estar indo para um host diferente do que você imagina.
Meu protótipo gerado por IA tem autenticação instável em produção — o que devo fazer?
Em apps gerados por IA, configurações de cookie e autenticação costumam estar inconsistentes entre local e produção, especialmente com subdomínios, callbacks OAuth e proxies. O caminho mais rápido é uma auditoria focada do fluxo real de login no domínio ao vivo para identificar o atributo ou etapa de redirecionamento que faz a sessão cair. Se quiser, FixMyMess pode revisar o código e reparar a autenticação e os cookies para que funcionem de forma confiável em produção, normalmente em 48–72 horas.