Auth

Login not working after deploy on Replit? Fix sessions and cookies

Short answer

  • Behind Replit's HTTPS proxy, Express needs app.set("trust proxy", 1), or secure session cookies are never sent.
  • Set a fixed SESSION_SECRET in the deployment, and store sessions in Postgres, not in memory.
  • Do not hard-code a cookie domain from development. Test login on each domain users can reach.

Login succeeds, the dashboard flashes, and the next click sends users back to the login page. Or they get logged out every time the app restarts. In the preview everything was fine. Session problems after deploy come from a short list of settings that only matter in production. Here they are.

Symptoms

  • Login redirects back to the login page in a loop.
  • Users are logged out after a few minutes, or after each deploy.
  • No Set-Cookie header in the login response, or the cookie is never sent back.
  • Logged in on one domain, logged out on the other.
  • 403 Forbidden on a published app with many cookies.

Likely causes

  1. cookie.secure is true but Express does not trust the proxy, so it thinks the request is HTTP and refuses to set the cookie.
  2. SESSION_SECRET is missing in production or random at startup, so every restart invalidates sessions.
  3. Sessions are stored in memory: lost on restart, and not shared between Autoscale instances.
  4. A cookie domain or sameSite value copied from development.
  5. Oversized headers from too many cookies, which Replit's help center lists as a cause of 403 errors.

Step-by-step fix

1. Trust the proxy

Add this before your session middleware. It tells Express to trust the X-Forwarded-Proto header from Replit's proxy.

app.set("trust proxy", 1);

2. Configure the session cookie for production

import session from "express-session";
import connectPg from "connect-pg-simple";
const PgStore = connectPg(session);

app.use(session({
  store: new PgStore({ conString: process.env.DATABASE_URL, createTableIfMissing: true }),
  secret: process.env.SESSION_SECRET,          // fixed value from deployment secrets
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: process.env.NODE_ENV === "production",
    httpOnly: true,
    sameSite: "lax",
    maxAge: 1000 * 60 * 60 * 24 * 7,
  },
}));

Leave domain unset unless you really share cookies across subdomains.

3. Set SESSION_SECRET once

Generate a long random value and save it in the deployment secrets. Never generate it at startup, and never reuse the development value in production.

4. Pick one canonical domain

A cookie set on yourapp.replit.app is not sent to yourdomain.com. Redirect secondary domains to the main one so users always log in on the same host.

5. Check frontend requests

If the frontend calls the API on the same domain with relative URLs, cookies are sent automatically. If it calls another origin, it needs credentials: "include" and a matching CORS setup. See CORS errors on Replit.

Copy-paste prompt for Replit Agent

Open a new Agent chat (a fresh chat keeps old attempts out of its context) and paste this:

Login works in the Replit preview, but in the published app users are logged out right away or loop back to the login page.
Please fix session handling for production:
1. Add app.set("trust proxy", 1) before the session middleware.
2. Store sessions in Postgres (connect-pg-simple) instead of memory.
3. Read SESSION_SECRET from the environment and fail at startup if it is missing; do not generate it at runtime.
4. Cookie: secure in production, httpOnly, sameSite "lax", no hard-coded domain.
5. Make sure frontend API calls use relative URLs on the same domain.
Show me the session config diff. Do not change the user table.

How to verify the fix

  • In DevTools → Network, the login response has a Set-Cookie header with Secure; HttpOnly.
  • After login, refresh three times and open a new tab: you stay logged in.
  • Republish the app: you are still logged in afterwards.
  • The sessions table in production has a row for your session.

Session settings are also security settings. Review them with the Replit Agent security checklist.

FAQ

Why does my Replit app log users out after every deploy?

Sessions are probably stored in memory, or the session secret changes at startup. Store sessions in the database and use a fixed SESSION_SECRET from the deployment secrets.

Why is my session cookie not set in production?

With secure cookies, Express only sets the cookie when it believes the request is HTTPS. Behind Replit's proxy, that requires app.set("trust proxy", 1).

Does Autoscale break in-memory sessions?

Yes. Autoscale can run several instances and restarts them, and memory is not shared or kept. Use a database-backed session store.

Get a free audit