Safeguard
Security Guides•

Session cookie or persistent cookie: what do Expires and Max-Age do?

A cookie without Expires or Max-Age is a session cookie, but browsers restore them. See how Max-Age wins, how to log out and what lifetime to pick.

Safeguard Security Team
3 min read

A cookie with no Expires or Max-Age is a session cookie, removed when the browser closes. One with either is persistent. If both are set, Max-Age wins. Session cookies are not a reliable timeout, because browsers with session restore bring them back.

The two kinds

MDN says that if Expires is unspecified, the cookie becomes a session cookie, and the session finishes when the client shuts down. Expires holds an HTTP-date timestamp; Max-Age holds a number of seconds. A zero or negative Max-Age expires the cookie immediately, and if both attributes are present, Max-Age has precedence.

AttributeMeaningNotes
NoneSession cookieRemoved when the browser shuts down
Max-Age=3600Persistent, one hourTakes precedence over Expires
Expires=<date>Persistent until dateBased on the server clock
Max-Age=0Delete nowUsed to clear a cookie

Why session cookies are not a safe timeout

MDN warns that many browsers have a session restore feature that saves all tabs and restores them the next time the browser opens, and session cookies are restored too, as if the browser was never closed. A user on a shared machine may therefore find a supposedly temporary login still active.

The server must own session lifetime. Keep an idle timeout and an absolute timeout in the session store, and reject expired sessions regardless of what the cookie says. The cookie lifetime is a convenience for the browser, not an enforcement point.

Clock skew and Expires

Expires is set against the server's clock, which may differ from the client's. MDN says Firefox and Chromium based browsers compensate using the Date header, but that the specification does not require correction. Max-Age avoids the problem, because it is relative. Prefer Max-Age for new code.

Choosing a lifetime

  1. Sensitive actions such as payments or admin: short idle timeout on the server, session cookie or a short Max-Age.
  2. Normal logged-in sessions: a moderate Max-Age, with a server side absolute limit and re-authentication for sensitive actions.
  3. Remember-me tokens: a separate cookie, a long lifetime, stored hashed on the server, revocable, and scoped to fewer actions than a full session.
  4. Preferences and analytics: persistent, non-sensitive, and not used for authentication.

Always set the cookie with Secure and HttpOnly where scripts do not need it, and choose SameSite on purpose.

How to log out properly

Delete the cookie by setting the same name, Path and Domain with Max-Age=0, and invalidate the session on the server. Matching Path and Domain matters, because a cookie with different attributes is a different cookie. You can also send Clear-Site-Data as described in Clear-Site-Data on logout.

Quick check

Does a session cookie expire when the tab closes?

No. It lasts until the browser shuts down, and may survive that through session restore.

Which should I set, Expires or Max-Age?

Max-Age for new code. It is relative, so server and client clock differences do not matter, and it takes precedence when both are present.

Safeguard's dependency scanning flags vulnerable session and cookie handling libraries, and its policies can block them in a pull request. Try the free scan at gold.safeguard.sh/scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.