Cierres de sesión aleatorios en producción: arreglos de cookies y sesiones
Los cierres de sesión aleatorios en producción suelen venir de la configuración de cookies y proxies. Aprende cómo SameSite, Secure, Domain y encabezados pueden hacer que las sesiones se pierdan en silencio.

Por qué ocurren cierres de sesión aleatorios al pasar a producción
Una sesión es cómo tu app recuerda a un usuario entre cargas de página. La mayor parte del tiempo, esa memoria vive en una cookie. O la cookie contiene un token firmado (común con JWT), o contiene un ID de sesión que apunta a datos de usuario almacenados en el servidor.
Los cierres de sesión “aleatorios” suelen significar que el navegador dejó de enviar la cookie de sesión a tu app. Nada se cae. Tu servidor simplemente deja de ver una sesión válida, trata al usuario como un desconocido y lo manda a la página de inicio de sesión.
Por eso las cosas pueden verse bien en localhost y desmoronarse en producción. Las pruebas locales suelen usar HTTP simple, un solo host y sin proxy delante. Producción añade dominios reales, HTTPS, CDNs y proxies inversos. Esos cambios afectan cómo los navegadores almacenan cookies y cuándo las anexan a las solicitudes.
La pérdida silenciosa de sesión suele verse así:
- Puedes iniciar sesión, pero te desconectas después de un refresco o unos clics.
- Una pestaña se mantiene iniciada y otra te devuelve al login.
- Solo pasa en producción, o solo en móvil/Safari.
- No hay errores útiles en la UI, solo “por favor, inicia sesión de nuevo”.
Los prototipos creados con IA son especialmente propensos porque a menudo traen configuraciones de cookie por defecto y snippets copiados que funcionaban en un entorno de vista previa. Los desencadenantes más comunes son dominio/path de cookie desajustados, valores por defecto de SameSite que bloquean ciertas solicitudes, cookies Secure mal configuradas y problemas de encabezados del proxy donde la app no se da cuenta de que el usuario está en HTTPS.
Si heredaste una base de código generada por IA que “casi funciona” pero sigue desconectando usuarios, esta suele ser una de las primeras áreas a auditar antes de reescribir la autenticación.
Conceptos básicos de cookies que deciden si las sesiones sobreviven
La mayoría de los problemas de sesión se reducen a unos pocos atributos de la cookie. Si cualquiera de ellos está mal, el navegador puede dejar de enviar silenciosamente la cookie que identifica al usuario.
Una cookie tiene un alcance. Las piezas que importan más son:
- Domain: qué nombres de host pueden recibir la cookie. Si la configuras para el dominio equivocado, o olvidas que
wwwy el dominio raíz son distintos, la cookie no se enviará en algunas solicitudes. - Path: qué rutas URL la reciben. Si es demasiado restrictivo, las páginas fuera de esa ruta actuarán como desconectadas.
- Expiration: cuánto dura. Una expiración faltante o muy corta puede hacer que un inicio de sesión se sienta inestable, especialmente tras un refresco o reinicio del navegador.
Hay dos duraciones comunes. Las cookies de sesión suelen desaparecer cuando el navegador se cierra. Las cookies persistentes tienen una fecha de expiración explícita y son las que usa típicamente “recordarme”. Si tu app espera un inicio de sesión persistente pero por error emite una cookie de sesión, los usuarios jurarán que se desconectaron “sin razón”.
La banderilla Secure es simple pero inflexible: cuando está activada, los navegadores solo envían esa cookie sobre HTTPS. Eso es correcto para producción, pero rompe si tu app cree estar en HTTP (a menudo por la configuración del proxy).
SameSite controla cuándo se envían las cookies a través de “límites de sitio”:
- Lax: se envía en la mayoría de la navegación normal, pero no en muchos flujos embebidos o cross-site.
- Strict: solo se envía en el mismo sitio. Más seguro, pero puede romper redirecciones de inicio de sesión.
- None: se envía cross-site, pero también debe ser Secure.
Un atributo incorrecto puede hacer que las cookies “desaparezcan”. La cookie puede seguir existiendo en el almacenamiento, pero no se adjunta a las solicitudes que importan. Tu servidor crea una nueva sesión y el usuario parece desconectado.
Configuración SameSite que desconecta usuarios sin aviso
SameSite es una regla de cookie que le dice al navegador cuándo puede enviar tu cookie de sesión. Si es demasiado estricta, la cookie se omite silenciosamente en ciertas solicitudes y tu app parece “desconectar aleatoriamente” a los usuarios.
Un escenario común: tu frontend está en app.example.com y tu API en api.example.com. Si tu login establece la cookie de sesión de una forma que el navegador trata como cross-site, la siguiente solicitud puede no incluir esa cookie. La API entonces piensa que el usuario es nuevo y crea una sesión fresca.
Los navegadores endurecieron sus valores por defecto en los últimos años. Muchos tutoriales antiguos asumen que las cookies se envían más libremente, así que una configuración que “funciona en localhost” se convierte en desconexiones en producción una vez que hay dominios reales, HTTPS y flujos con muchas redirecciones.
Qué se rompe con más frecuencia
Los problemas aparecen en flujos que no son un simple click-through en el mismo sitio: inicios de sesión por OAuth (Google, GitHub), magic links desde email, widgets embebidos dentro de otro sitio y algunos setups de subdominios donde las redirecciones rebotan entre hosts.
En muchas apps normales, SameSite=Lax es suficiente. Lax usualmente permite cookies en navegaciones de nivel superior (como clicar un enlace a tu sitio) pero las bloquea en muchas solicitudes en segundo plano o embebidas. Si tu flujo de auth depende de cookies durante una devolución de llamada por redirección o dentro de un iframe, Lax todavía puede fallar.
Generalmente necesitas SameSite=None cuando tu cookie debe enviarse en un contexto claramente cross-site (embeds, algunos procesos OAuth y ciertos patrones de API cross-domain). Pero SameSite=None tiene un requisito estricto: debe ir acompañado de Secure, lo que significa que la cookie solo se enviará por HTTPS.
Una regla práctica:
- Por defecto usa
SameSite=Laxpara apps web estándar en un solo sitio. - Usa
SameSite=None; Securepara embeds, requests cross-site o callbacks OAuth complicados. - Evita
SameSite=Strictpara sesiones de login salvo que entiendas totalmente los efectos secundarios. - Después de cambiar SameSite, prueba todo el flujo de login en el dominio de producción real.
Banderilla Secure y trampas de HTTPS
La bandera Secure de la cookie indica al navegador enviar la cookie solo por HTTPS. Eso es bueno para seguridad, pero provoca comportamientos confusos cuando aún llega tráfico HTTP a tu app.
Un fallo clásico: un usuario llega a la versión HTTP de tu dominio, tu servidor intenta establecer una cookie de sesión Secure y luego redirige a HTTPS. Los navegadores ignoran las cookies Secure establecidas sobre HTTP. La redirección funciona, pero la sesión nunca se mantiene, así que el usuario parece desconectado de inmediato.
Las pruebas locales lo ocultan porque puede que ejecutes todo sobre HTTP en localhost. Luego despliegas detrás de HTTPS, activas Secure y algunos usuarios empiezan a perder sesiones porque una redirección en el edge, una regla del CDN o un proxy aún permiten HTTP para la primera petición.
Diferencias entre staging y producción
Staging a menudo tiene URLs, ajustes TLS o reglas de proxy diferentes. Si staging fuerza HTTPS pero producción permite ambos HTTP y HTTPS, el comportamiento de las cookies será inconsistente.
También vigila entornos donde tu app cree que está en HTTP porque un proxy inverso termina TLS. Si la app no confía en los encabezados reenviados, puede establecer cookies y redirecciones basadas en el esquema equivocado.
Cómo saber que el navegador está rechazando la cookie
Síntomas comunes:
- Ves
Set-Cookieen la respuesta, pero la cookie nunca aparece en el almacenamiento del navegador. - El login “funciona” para una petición, luego la siguiente carga como desconectado.
- Solo algunos usuarios se ven afectados (a menudo los que usan un marcador antiguo o escriben el dominio sin HTTPS).
- DevTools muestra advertencias como “This Set-Cookie was blocked” o “Secure cookie over insecure connection.”
Si estás lidiando con una base de código generada por IA que establece cookies en varios sitios, también es común encontrar configuraciones duplicadas o en conflicto que hacen que esto parezca aleatorio hasta que rastreas la primera petición.
Errores de Domain y Path que causan pérdida de sesión
A veces el navegador hace exactamente lo que le dijiste. Simplemente no coincide con lo que querías.
Las cookies host-only son el valor por defecto: la cookie está ligada al host exacto que la estableció (por ejemplo, app.example.com). Las cookies con Domain son más amplias: si estableces Domain=example.com, la cookie puede enviarse a app.example.com, api.example.com y otros subdominios. Ninguna es “mejor” por defecto, pero mezclarlas entre servicios puede crear huecos de sesión.
Subdominios: la división clásica que rompe sesiones
Si tu frontend vive en app.example.com y tu API en api.example.com, una cookie host-only establecida por la API no se enviará al host del frontend, y viceversa. El usuario parece conectado en un lado y desconectado en el otro.
También vigila valores Domain erróneos. Domain=localhost no es una configuración de producción real, y Domain=www.example.com no cubrirá app.example.com. Si usas un dominio personalizado o un CDN, el host “real” que el navegador ve puede diferir de lo que tu app asume.
Path: un detalle pequeño con gran impacto
Las cookies solo se envían en URLs que coincidan con su Path. Si configuras Path=/api y luego tu app navega a /dashboard, esa cookie no se incluirá. Esto aparece cuando el código establece una cookie en un grupo de rutas y la lee en otro lugar.
Algunas comprobaciones de sentido común:
- Asegúrate de que el Domain de la cookie coincida con donde esperas que se envíe.
- Solo establece
Domain=example.comsi realmente necesitas sesiones compartidas entre subdominios. - Mantén
Path=/a menos que tengas una razón sólida para no hacerlo. - Prueba el login en cada subdominio y tanto en el dominio “naked” como en el
www.
Encabezados de proxy inverso que rompen cookies en producción
Muchas apps están detrás de un proxy inverso en producción (Cloudflare, Nginx, Vercel, Render, Fly.io, Railway). El proxy termina HTTPS y reenvía la petición a tu app. Si tu app no entiende que está detrás de un proxy, puede pensar que cada petición es HTTP o que el host es un nombre interno. Ese desajuste suele aparecer como “cierres de sesión aleatorios”.
La causa habitual es simple: tu app construye la configuración de cookies a partir de la petición que ve. Si cree que la petición es HTTP, puede omitir Secure o generar la URL de redirección equivocada. Si cree que el host es otro, puede establecer una cookie para el dominio equivocado. El navegador entonces ignora la cookie o la mantiene limitada a otro sitio.
Estos encabezados de proxy deciden qué cree tu app:
X-Forwarded-Proto: esquema original (HTTP vs HTTPS)X-Forwarded-Host: host original (tu dominio real)X-Forwarded-For: IP original del cliente (a menudo se usa para límites de tasa y reglas de seguridad)
Un ejemplo concreto: un proxy envía X-Forwarded-Proto: https, pero tu app lo ignora. El middleware de sesión cree que está en HTTP y establece una cookie no Secure. En un sitio HTTPS, los navegadores pueden rechazar o manejar mal esa cookie, así que los usuarios se desconectan tras un refresco o redirección.
La solución suele ser un ajuste del framework (comúnmente llamado “trust proxy”). Ten cuidado: confiar en encabezados de proxy desde internet abierto es inseguro. Solo confía en ellos cuando un proxy real delante de ti sea lo único que pueda alcanzar tu app.
Paso a paso: configurar cookies y sesiones correctamente
Si ves cierres de sesión aleatorios en producción, no adivines. Cambia una variable a la vez para poder identificar qué lo arregló.
Empieza por fijar la dirección pública real. Anota la URL exacta que escriben los usuarios (incluyendo si usas www). Confirma si el sitio siempre usa HTTPS desde la primera petición y si algo puede alcanzar un endpoint HTTP antes de redirigir.
Luego decide si realmente necesitas cookies cross-site. Normalmente las necesitas cuando la autenticación ocurre en un dominio distinto (común en OAuth), cuando tu API está en un subdominio separado y compartes sesiones, o cuando embebes la app dentro de otro sitio.
Después alinea la configuración de tus cookies con esa realidad:
- Para apps de un solo sitio,
SameSite=Laxsuele ser suficiente. - Para flujos cross-site, puede ser necesario
SameSite=None, pero debe ir acompañado deSecure. - Establece
Securesegún lo que los usuarios ven (HTTPS), no según lo que tu servidor cree que ve. - Sé intencional con
DomainyPath. Si no necesitas compartir entre subdominios, no pongasDomain. ManténPath=/en la mayoría de los casos.
Finalmente, maneja la causa más común del “funciona localmente”: proxies. Confirma que tu proxy reenvía los encabezados correctos y que tu app está configurada para leerlos. Luego prueba como un usuario nuevo: ventana de incógnito, reinicio completo del navegador y el flujo de login exacto incluyendo redirecciones.
Trampas comunes (especialmente en bases de código generadas por IA)
Las apps creadas por IA a menudo funcionan en localhost y luego empiezan a desconectar en producción. La brecha suele ser el comportamiento de cookies que cambia cuando aparecen HTTPS real, dominios reales y un proxy inverso.
Un fallo silencioso común es establecer SameSite=None sin Secure. Muchos navegadores ignorarán esa cookie por completo, así que la sesión nunca se mantiene. Puede parecer que el login funcionó (ves Set-Cookie), pero la siguiente petición llega sin sesión.
Los errores de Domain son otro gran problema. Los generadores a veces adivinan un Domain de cookie o arrastran un valor de preview/localhost. Si la cookie está limitada al host equivocado (o demasiado amplia), el navegador no la enviará donde tu app la espera.
El manejo de HTTPS en el borde también complica al equipo. Si el tráfico llega a un balanceador que termina TLS, tu app podría creer que las peticiones son HTTP a menos que manejes correctamente los encabezados reenviados. Eso conduce a cookies y redirecciones que no coinciden con lo que hace el navegador.
Finalmente, las bases generadas por IA suelen mezclar sistemas de auth sin darse cuenta: una cookie de sesión del framework más una cookie JWT personalizada, o múltiples capas de middleware que mutan cookies. Eso crea un comportamiento de “último escritor gana” que se siente aleatorio.
Una forma rápida de detectar estos problemas es comparar atributos de cookies entre local y producción (SameSite, Secure, Domain, Path) y luego observar qué ocurre durante las redirecciones después del login.
Comprobaciones rápidas antes de cambiar nada
Antes de tocar flags de cookie o reescribir auth, pasa unos minutos confirmando qué está ocurriendo realmente. Muchos informes de “sesión expirada” son en realidad “el navegador dejó de enviar una cookie”.
Si puedes reproducir la desconexión en un par de minutos, abre DevTools (Application/Storage) y observa la cookie de sesión después de iniciar sesión. Usa una línea base simple:
- Inicia sesión y confirma que la cookie de sesión aparece.
- Refresca dos veces y confirma que la cookie sigue existiendo.
- Lanza una llamada a la API y confirma que la cookie se envía con la solicitud.
- Cierra sesión y vuelve a entrar y confirma que no terminas con dos cookies similares.
Luego confirma si la primera petición siempre es HTTPS. Si el primer impacto es HTTP y luego redirige, puedes acabar con cookies establecidas de una forma que el navegador rechace.
Si tu app y API viven en subdominios diferentes (o dominios distintos), anótalo. Las reglas cross-site y el alcance de la cookie suelen explicar por qué los inicios de sesión “a veces se mantienen”.
También verifica qué piensa el servidor sobre la URL externa. Detrás de un proxy, encabezados reenviados incorrectos pueden hacer que la app crea que está en el esquema o host equivocado.
Finalmente, compara navegadores. Si solo pasa en móvil, o solo en Safari vs Chrome, SameSite y reglas cross-site son un fuerte sospechoso.
Escenario de ejemplo: preview funciona, producción sigue desconectando
Un patrón común: una app creada con IA corre en app.example.com, llama a una API en api.example.com y ambos están detrás de un proxy inverso. El login parece funcionar, pero la sesión no se mantiene.
En la preview todo parecía bien porque la app y la API vivían en un host temporal. Las cookies eran simples y las redirecciones se quedaban en el mismo origen.
Al salir a producción, los usuarios inician sesión, ven el dashboard brevemente y luego son devueltos al login después de una redirección (a menudo tras OAuth, magic link por email o un paso de “terminar registro”). No hay error obvio, solo pérdida silenciosa de sesión.
Lo que suele pasar es alguna combinación de:
- La API establece la cookie de sesión con
SameSite=None, pero le faltaSecure. - El proxy no reenvía correctamente
X-Forwarded-Proto, o la app no confía en él. - El servidor cree que la petición es HTTP, así que evita cookies Secure o genera redirecciones que rebotan entre HTTP y HTTPS.
Los navegadores modernos tratan las cookies SameSite=None como cross-site. Si no están marcadas también como Secure, el navegador puede descartarlas. Así, la respuesta dice que estableció una cookie, pero el navegador nunca la almacena y la siguiente petición llega sin sesión.
La solución suele ser aburrida pero definitiva:
- Asegura que el proxy reenvíe los encabezados forward correctos (especialmente
X-Forwarded-Proto). - Usa
SameSite=None; Securecuando se requiera comportamiento cross-site. - Confirma el alcance de la cookie: establece un Domain solo si verdaderamente necesitas compartir sesión entre subdominios y mantén
Pathsensato (generalmente/).
Próximos pasos: estabilizar tu app creada por IA en producción
Si sigues viendo desconexiones después de ajustar flags de cookie, es hora de dejar de adivinar y hacer una revisión enfocada de auth/sesión. Una suposición equivocada (como confiar en el encabezado de proxy equivocado o establecer una cookie en el host incorrecto) puede deshacer varios “arreglos” que parecían correctos en un entorno de preview.
Antes de cambiar más código, recopila un pequeño conjunto de hechos:
- Los atributos exactos de la cookie que se están estableciendo (nombre, Domain, Path, SameSite, Secure, HttpOnly, Max-Age)
- Variables de entorno relacionadas con auth/sesiones (secreto de sesión, base URL, dominio de cookie, proxies de confianza)
- Tu configuración de proxy/CDN y qué encabezados añade (especialmente
X-Forwarded-ProtoyX-Forwarded-Host) - Pasos de reproducción claros (dispositivo/navegador, flujo de login, qué página lo dispara)
- Un par de muestras de request/response de producción (respuesta de login y la primera solicitud que falla)
Si esto es un prototipo generado por IA de herramientas como Lovable, Bolt, v0, Cursor o Replit, los problemas de cookie/proxy suelen aparecer junto a problemas mayores como patrones de auth mezclados y secretos filtrados.
Si quieres una segunda opinión, FixMyMess (fixmymess.ai) se centra en tomar apps generadas por IA y hacerlas listas para producción. Una auditoría corta suele ser suficiente para localizar el alcance de cookie o el desajuste de proxy exacto para que los inicios de sesión sean estables.
Preguntas Frecuentes
Why does my app log users out “randomly” after launch?
Most “random” logouts happen when the browser stops sending your session cookie. The app doesn’t crash; it just receives a request without a valid session and treats the user as logged out.
Why does it work on localhost but fail in production?
Localhost is usually one host, often plain HTTP, and often without a reverse proxy. Production adds real domains, HTTPS, redirects, CDNs, and proxies, and those differences can change whether cookies are stored and attached to requests.
How can I quickly confirm the logout is a cookie problem?
Start by inspecting the session cookie in DevTools after login and after a refresh. Confirm it exists, has the expected attributes (Domain, Path, SameSite, Secure, expiration), and is actually included on the requests that fail.
What SameSite setting should I use to stop logouts?
Use SameSite=Lax for a typical single-site app, because it usually keeps logins stable while adding some protection. Use SameSite=None only when you truly need cookies in cross-site contexts, and then pair it with Secure.
Why does `SameSite=None` sometimes make sessions disappear?
The browser will ignore a SameSite=None cookie if it isn’t also marked Secure. That often looks like login succeeded (you saw Set-Cookie), but the cookie never gets stored, so the next request arrives with no session.
How does the Secure flag cause immediate logout after login?
A Secure cookie is only stored and sent over HTTPS. If the first hit is HTTP (even briefly before redirect), the browser can reject the cookie, so the user looks logged out immediately after the redirect to HTTPS.
What does “trust proxy” have to do with session stability?
If your app is behind a proxy and doesn’t trust forwarded headers, it may think requests are HTTP or on the wrong host. That can lead to cookies being set with the wrong scheme or domain, which browsers then don’t send back consistently.
Can a wrong cookie Domain or Path cause logouts on certain pages?
If the cookie Domain is too narrow (like only www), some pages or services won’t receive it. If the Path is too specific (like /api), pages outside that path won’t send the cookie, and users will look logged out on those routes.
Why do I stay logged in on one subdomain but not another?
Yes. A host-only cookie set on api.example.com won’t be sent to app.example.com, so one side may see a session while the other doesn’t. If you need a shared session across subdomains, align Domain and SameSite settings intentionally.
What’s different about AI-built apps that makes this problem common, and how can FixMyMess help?
AI-generated projects often mix auth approaches (multiple session layers, JWT cookies plus framework sessions) and ship default cookie flags that only worked in a preview environment. A focused audit of cookie attributes, proxy headers, and redirects usually finds the exact mismatch quickly.