Cookies and Web Storage
A web application can keep data in your browser in three common places. Cookies are small name–value pairs that the server sets with a Set-Cookie response header and the browser sends back in a Cookie request header. Local storage and session storage, together called web storage, are key–value stores that only the page's JavaScript reads and writes; nothing in them reaches the server unless a script sends it.
A shop, for example, can use all three: a cookie keeps you logged in, local storage keeps your cart after you close the browser, and session storage keeps the checkout step of one tab. You met them in the Application panel in the lesson on browser DevTools; here you learn the rules that decide what survives a reload, a new tab, a restart and a logout, so you can predict the result before you test it.
Why it matters
Defects in this area are about the wrong data surviving or the right data disappearing: a user who is still logged in after logout, a cart that empties on refresh, a checkout that breaks in a second tab, or the previous user's address on a shared computer. They rarely appear in a happy-path run, because nobody closes the tab, restarts the browser or switches account.
Browser storage is also a security and privacy surface. A session cookie without HttpOnly can be read by any script on the page, a token in local storage stays on the device after the user leaves, and personal data kept in the browser can outlive its purpose. Knowing how each mechanism behaves turns these risks into planned tests.
How the browser keeps a session
HTTP is stateless: each request stands alone. To keep you logged in, the server creates a session at login, keeps its data on the server and gives the browser only a random session identifier, usually in a cookie such as sid. The browser sends it with every request and the server looks the session up. The browser holds the key, not the session.
Some single-page applications instead receive a token, often a JWT (JSON Web Token: a signed string that carries information such as the user's identity and an expiry time), keep it in web storage or in memory and add it to an Authorization header themselves. Any script on the page can read web storage, which is why OWASP advises against keeping session identifiers or tokens there; an HttpOnly cookie is out of reach of scripts. Either way, the same session checks apply:
- Login: the session identifier changes at login, so a value planted before login is useless afterwards.
- Logout: the server invalidates the session. Deleting the cookie is not enough; a request replayed with the old identifier must be refused.
- Timeouts: after the agreed idle and absolute time the session ends, and the user lands on the login page with a clear message, not an error.
- Tabs: a session cookie is shared by every tab, so after logout in one tab the others must show the login page on their next action.
Local storage and session storage
Web storage is defined in the HTML Standard. Both stores keep string keys and string values, are separated by origin (scheme, host and port, so the http and https versions of a site do not share data) and are used only from JavaScript, for example localStorage.setItem('cart', value). Nothing is sent to the server automatically. They differ in lifetime and sharing:
- Local storage is shared by every tab of the origin and has no expiry: it survives browser restarts until a script, the user or the browser clears it.
- Session storage belongs to one tab. It survives reloads and is cleared when the tab closes; a new tab gets its own store, while duplicating a tab copies it.
- Values are strings only. An object saved without first turning it into text with
JSON.stringifybecomes[object Object], a defect you can spot in the Application panel. - Space per origin is limited, typically a few megabytes depending on the browser. When it is full,
setItemthrows an error the application must handle. - A private window gets separate storage, which the browser discards when the private session ends.
HttpOnly; local storage stays in the browser across tabs and restarts, session storage in one tab until it closes.CookieRFC 6265
Set by the server with Set-Cookie, or by a script unless it is HttpOnly
- Sent to the server:
- Automatically, with every matching request
- Shared between:
- All tabs of the browser
- Lifetime:
- Until
ExpiresorMax-Age; without them, until the browser session ends - Readable by page scripts:
- Not when
HttpOnly - First check:
- After logout, the server refuses the old session value
Local storagelocalStorage
String keys and values written by the page's JavaScript
- Sent to the server:
- Never automatically
- Shared between:
- All tabs of the same origin
- Lifetime:
- No expiry: until a script, the user or the browser clears it
- Readable by page scripts:
- Always
- First check:
- User B never sees what user A left behind
Session storagesessionStorage
The same interface, scoped to one tab
- Sent to the server:
- Never automatically
- Shared between:
- One tab only; duplicating the tab copies it
- Lifetime:
- Until the tab closes; survives reloads
- Readable by page scripts:
- Always
- First check:
- A new tab starts without the old tab's step
Lifetimes shown are the defaults: a browser that restores the previous session on start-up also restores session cookies and session storage.
Worked example: login, cart and checkout
A shop sets sid as a session cookie, sets remember as a 30-day cookie only when the user ticks "Remember me", keeps the cart in local storage and the checkout step in session storage. Before testing, the tester predicts each result from the rules above, then checks it in the page and in the Application panel. The table assumes the user ticked "Remember me"; each cell is an expected result, and each row becomes a test case.
Reopening the browser without "Remember me" means logging in again with the cart still there; with it, the shop issues a new sid through remember, which must stop working after 30 days. Whether the cart should survive logout is a product decision, not the tester's: raise it as a question and record the answer in the test case.
Action sid remember cart (local) step (session)
Reload the page kept kept kept kept
Open the shop in a new tab sent sent same cart empty
Close and reopen the browser gone (1) kept kept gone (1)
Log out deleted deleted decide (2) gone
Clear site data gone gone gone gone
Old sid replayed after logout -> login page or 401, never account data
Shop after clearing site data -> loads logged out, empty cart, no error
(1) unless the browser restores the previous session on start-up
(2) product decision: on a shared computer the next user sees the cartTesting persistence, clearing and privacy
Use a test account, and edit or clear stored data only on systems you are allowed to test. Cover five areas; the Console lines after the list show how to read and change web storage directly.
- Persistence: reload, new tab, duplicated tab, browser restart and the moment of expiry, each compared with the requirement.
- Clearing: delete one cookie or key, then clear all site data. The application must start cleanly, without a blank page or a script error.
- Old and corrupted values: an invalid or old-format value, as after a release that changed the format, must not break returning users.
- Shared computer: log in as user A, log out, log in as user B. Nothing of A — name, address, cart, searches, drafts — may appear for B.
- Privacy: passwords and card numbers never belong in cookies or web storage, other personal data only while a feature needs it, and session cookies carry
SecureandHttpOnly. If the site asks for cookie consent, refuse non-essential cookies and confirm in the Application panel that none were set.
localStorage.getItem('cart') // read what the shop stored
localStorage.setItem('cart', '{bad') // invalid JSON: reload, does the page recover?
sessionStorage.clear() // empty this tab's session storage
document.cookie // HttpOnly cookies are not listedCommon mistakes
- Testing in one long-lived tab only, so new-tab, restart and logout behaviour is never observed.
- Passing logout because the cookie disappeared, without checking that the server refuses the old session identifier.
- Assuming session storage behaves like a session cookie: the cookie is shared by all tabs and goes to the server, session storage belongs to one tab and stays in the browser.
- Reporting a session cookie that survived a restart without checking whether the browser restores the previous session on start-up.
- Testing only with a clean browser, so returning users with old cookies or an old storage format are never simulated.
- Pasting cookie values, tokens or storage contents with personal data into a bug report instead of masking them.
The QA perspective
Ask early what the feature keeps in the browser, where and for how long. A short table — name, mechanism, attributes, lifetime, what logout does — is a test basis that developers, the product owner and security reviewers can all check. Open points such as "Should the cart survive logout?" or "How long does Remember me last?" are requirement questions, not tester decisions.
In a bug report, name the exact cookie or key, its attributes or value as the Application panel shows them with secrets masked, the browser and its version, and the step that changed it: login, new tab, restart or logout. Storage behaviour often regresses after framework upgrades and after releases that change stored formats, so keep these checks in the regression suite and run them on every supported browser.
Practice exercise
Predict and check what a staff portal keeps
After login, a staff portal sets the cookies and storage below. For each item, say how long it lives and whether it is shared between tabs. Then list the defects or risks you would report, and three test cases that confirm logout works.
Response to POST /login
Set-Cookie: session=Qm91c2E1Vq; Path=/
Set-Cookie: theme=dark; Max-Age=86400; Path=/; SameSite=Lax
localStorage on https://portal.example
user {"name":"Sara Ali","email":"sara@example.com","token":"eyJhbGciOi..."}
draft "Notes for the Sunday meeting"
sessionStorage on https://portal.example
wizard {"step":3}- Classify each item: cookie, local storage or session storage; persistent or session.
- Predict what remains after a new tab, a browser restart and a logout.
- Check each cookie's attributes and each storage key's contents for security and privacy problems.
- Write the logout test cases with their expected results.
Show the model answer
session has no Expires or Max-Age, so it is a session cookie shared by all tabs and removed when the browser session ends. theme is persistent: it lives 86,400 seconds (one day), is shared by all tabs and survives a restart within that day. user and draft stay in local storage across tabs and restarts until cleared. wizard exists only in the tab that created it: a new tab starts without it, and it disappears when that tab closes.
Defects and risks: session lacks Secure and HttpOnly, so it can travel over plain HTTP and any script can read it; it also has no explicit SameSite. The user key keeps a token any script can read, and the user's personal data stays on the device after the browser closes. Pasting the two Set-Cookie lines into the Cookie Analyzer lists the missing attributes.
Question for the product owner: should draft survive logout? On a shared computer the next user would see Sara's notes.
Logout tests: (1) after logout, session is deleted and user is removed from local storage; (2) a request replayed with the old session value, or with the old token, returns the login page or 401 Unauthorized, not portal data; (3) after logout in one tab, the other tab shows the login page on its next action.
Frequently asked questions
Is a session cookie the same as session storage?
No. A session cookie is a cookie without Expires or Max-Age: the browser sends it to the server, shares it across all tabs and removes it when the browser session ends. Session storage is a JavaScript store that belongs to one tab, is never sent to the server automatically and is cleared when that tab closes.
Why is my session cookie still there after I restarted the browser?
Many browsers can restore the previous session on start-up, and they then restore session cookies too, as if the browser had never closed. Check the browser's start-up setting, test the requirement with session restore turned off, and record the setting in the bug report.
Where should an application keep the login token?
That is a design decision for developers and security reviewers, but a tester should know the trade-off: an HttpOnly, Secure cookie cannot be read by scripts, while anything in web storage can. A cookie, on the other hand, is sent automatically, so it needs protection against cross-site request forgery (CSRF): anti-CSRF tokens, with SameSite as an extra layer. Whatever the choice, test that the credential is cleared at logout and refused by the server afterwards.
References
- RFC 6265: HTTP State Management MechanismHow cookies are set and sent: the Set-Cookie attributes (Expires, Max-Age, Domain, Path, Secure, HttpOnly) and their scope rules.
- HTML Living StandardThe HTML language, including named character references (entities) and the parsing rules browsers follow.
- OWASP Cheat Sheet Series: Session ManagementSession identifier entropy, cookie attributes, expiry, renewal after login and logout handling.
- Using HTTP cookies — MDNCookie lifetime, scope, the Secure/HttpOnly/SameSite attributes and their security implications.
Practise with Mutqan tools
Parse Set-Cookie headers and check Secure, HttpOnly, SameSite, Domain, Path, expiry and size best practices.
Parse raw HTTP request/response headers into a structured table with explanations.
Decode JWT header and payload, inspect claims and check expiration — entirely in your browser.
Go deeper
Your progress on this topic
Not started
Mark the topic complete when you have studied it and done the exercise.
Sign in to track your progress
Mark topics complete, continue where you left off and unlock specialisation exams.