Enforce session timeouts on the server, set both an idle and an absolute limit, issue a new session ID whenever privilege changes, and invalidate the session on the server at logout. Deleting the cookie in the browser is not enough, because a stolen ID would still work.
Timeouts
OWASP gives common ranges for idle timeouts: 2 to 5 minutes for high-value applications and 15 to 30 minutes for low-risk ones. For an absolute timeout, a maximum lifetime regardless of activity, its example for a full workday is 4 to 8 hours.
NIST ties these to assurance level. At AAL2 the overall timeout should be no more than 24 hours and inactivity no more than 1 hour. At AAL3 the limits are 12 hours and 15 minutes. See AAL1, AAL2 and AAL3 explained.
All timeouts must be enforced server side. A timer in client JavaScript is a convenience for the user, not a control.
Regenerate the ID at every privilege change
Issue a new session ID and destroy the old one after login, password change, permission change, or a switch to an admin role. This blocks session fixation, where an attacker plants a known ID before the victim logs in. OWASP adds that if the server receives an ID it did not generate, it should reject it, issue a new one and log the event as suspicious.
What a proper logout does
- Invalidate the session record on the server. OWASP calls this mandatory.
- Clear the cookie with an empty value and a past expiry date.
- Show a logout control on every page.
- Consider a Clear-Site-Data response header for cache, cookies and storage.
- Send Cache-Control no-store on responses with session data. OWASP notes that no-cache is not the same thing.
- Do not rely on browser-close events, which are unreliable.
Where not to keep the session
OWASP says not to put session IDs or tokens in localStorage or sessionStorage, because any XSS on the origin can read them. Prefer HttpOnly cookies, or a backend-for-frontend pattern.
For cookie flags such as Secure and SameSite, see our existing cookie security guide.
To verify all of this, write three tests. First, log in, log out, then replay the old cookie against the server, and confirm it is rejected. Second, log in, wait past the idle limit, and confirm the next request fails. Third, change the password in one browser and confirm the session in another browser ends. Automated tests catch regressions when frameworks or proxies change.
Quick check
Should I log users out when the tab closes?
You cannot rely on it. Use server-side idle and absolute timeouts and an explicit logout.
Do password changes need a new session?
Yes. OWASP lists password changes among the privilege changes that should regenerate the ID.
Sources
Last reviewed: 19 October 2026.