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.
| Attribute | Meaning | Notes |
|---|---|---|
| None | Session cookie | Removed when the browser shuts down |
Max-Age=3600 | Persistent, one hour | Takes precedence over Expires |
Expires=<date> | Persistent until date | Based on the server clock |
Max-Age=0 | Delete now | Used 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
- Sensitive actions such as payments or admin: short idle timeout on the server, session cookie or a short Max-Age.
- Normal logged-in sessions: a moderate Max-Age, with a server side absolute limit and re-authentication for sensitive actions.
- Remember-me tokens: a separate cookie, a long lifetime, stored hashed on the server, revocable, and scoped to fewer actions than a full session.
- 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.