Client Side Security
Client-side security means protecting the data, tokens, sessions, and browser storage used by a frontend application.
In the browser, data can be stored in places like localStorage, sessionStorage, IndexedDB, cookies, and cache storage.
Frontend App -> Browser Storage -> Tokens / Session Data / Cached Data
The main idea is simple:
Do not trust the client completely.
Store less data.
Protect what must be stored.
Expire sensitive values.
Verify that data was not changed.
One-line idea: Client-side security means storing less sensitive data in the browser, protecting what must be stored, expiring tokens, validating integrity, respecting storage limits, and managing sessions safely.
Core Concepts
Why It Matters
Client-side storage is useful, but it can become risky if sensitive data is stored carelessly.
Examples of sensitive data:
- passwords
- tokens
- session IDs
- personal user data
- payment-related data
- identity-related data
If this data is exposed or modified, it can affect the user account, application security, and data correctness.
| Area | Why It Matters |
|---|---|
| Sensitive data storage | Browser storage can be inspected or misused |
| Authentication | Tokens and sessions must be controlled properly |
| Data integrity | Stored data should not be changed silently |
| Storage limit | Too much client-side data can hurt performance or cause data loss |
| Session management | Sessions and cookies must be handled safely |
Core Flow
Need to store data in browser?
↓
Check if it can stay on the server
↓
If client storage is required
↓
Store only required data
↓
Encrypt sensitive data if needed
↓
Set token/session expiry
↓
Verify data integrity
↓
Check storage usage and quota
↓
Manage session cookies safely
Main Security Goals
Client-side security mainly focuses on five important goals.
| Goal | Simple Meaning | Main Practice |
|---|---|---|
| Sensitive Data Protection | Avoid exposing private data in the browser | Prefer server storage, encrypt if required, set expiry |
| Authentication Safety | Login/session should be secure | Use JWT/OAuth/OIDC, session expiry, and MFA |
| Data Integrity | Data should not be changed secretly | Use checksum or integrity checks |
| Storage Control | Browser storage should not exceed limits | Track usage and avoid storing too much data |
| Session Management | Sessions and cookies should be safe | Use proper cookie flags and server-managed sessions |
Practical Examples
Sensitive Data Storage
The safest rule is:
Try to store sensitive data on the server first.
Client storage should only contain data that is actually required by the frontend.
Bad example:
localStorage.setItem("password", "mySecretPassword");
This is unsafe because the browser is not a fully trusted place.
Better example:
const sensitiveData = "cached-profile-data";
const encryptedData = encryptFunction(sensitiveData);
localStorage.setItem("encryptedData", encryptedData);
This is better than storing raw data, but it does not make client storage completely safe. Do not store passwords in browser storage, even encrypted, because client-side keys and code can be exposed.
Encryption reduces risk.
Server-side storage is still safer for truly sensitive data.
Token Expiry
Tokens should not remain valid forever.
If a token is stored on the client, it should have a short expiration time so the risk window is smaller.
const token = generateToken();
const tokenExpirationTime = 15 * 60 * 1000; // example: 15 minutes
localStorage.setItem("token", token);
setTimeout(() => {
localStorage.removeItem("token");
}, tokenExpirationTime);
Simple idea:
Token created -> token stored -> token expires -> token removed/invalidated
Client-side removal is only local cleanup. The token must also expire or be invalidated on the server side.
| Without Token Expiry | With Token Expiry |
|---|---|
| Token may stay usable for a long time | Token becomes unusable after a fixed time |
| Higher risk if token is leaked | Lower risk window |
| Session may stay active unnecessarily | Session is controlled better |
Authentication
Authentication should use standard and secure mechanisms.
The PDF highlights:
- JWT/OAuth or OpenID Connect depending on the login flow
- session token expiry
- MFA, meaning multi-factor authentication
User logs in
↓
Server verifies user
↓
Server issues token/session
↓
Client stores only what is required
↓
Token/session expires after a fixed time
MFA adds another layer of security because the user needs more than just a password.
Password only -> weaker
Password + MFA -> stronger
Data Integrity
Data integrity means data has not been changed in an unauthorized way.
It applies to data:
- in storage
- during processing
- while in transit
Simple meaning:
Data integrity = data is still the same as expected
For browser storage, this means we may need to verify whether stored data was modified.
Checksum for Data Integrity
A checksum can be used to check whether stored data changed accidentally. For security against tampering, use a keyed MAC/signature or server-side verification because an attacker who can edit client storage may also edit a plain checksum.
const dataToStore = "myData";
const checksum = calculateChecksum(dataToStore);
localStorage.setItem("data", dataToStore);
localStorage.setItem("checksum", checksum);
const storedData = localStorage.getItem("data");
const storedChecksum = localStorage.getItem("checksum");
if (calculateChecksum(storedData) === storedChecksum) {
console.log("Data integrity is intact");
} else {
console.log("Data may have been changed");
}
Important difference:
Encryption hides data.
Checksum detects accidental data changes.
MAC/signature detects unauthorized changes.
So, encryption, checksum, and MAC/signature solve different problems.
Storage Limit
Browser storage is limited.
The PDF mentions two major impacts of storing too much data on the client:
- It affects performance.
- Storing more data than the browser capacity can lead to data loss.
More client-side data
↓
More browser storage usage
↓
Possible performance impact
↓
Quota errors or data loss
Client Storage Limits
Common browser storage limits mentioned in the PDF:
| Storage Type | Approximate Limit |
|---|---|
localStorage | 5-10 MB |
sessionStorage | 5-10 MB |
IndexedDB | 50-100 MB |
| Cookie | 4 KB-20 KB |
| Cache API | Browser-managed |
Use larger storage like IndexedDB only when the app really needs it, such as for offline data or structured client-side data.
Checking Storage Usage
The browser StorageManager API can be used to estimate current usage and available quota.
function hasEnoughSpaceForData() {
if ("storage" in navigator && "estimate" in navigator.storage) {
navigator.storage.estimate().then((estimate) => {
console.log(
"Usage: " + (estimate.usage / 1024 / 1024).toFixed(2) + " MB",
);
console.log(
"Quota: " + (estimate.quota / 1024 / 1024).toFixed(2) + " MB",
);
});
} else {
console.log("StorageManager API is not supported in this browser.");
}
}
This is useful when the frontend stores data for:
- offline support
- cached API responses
- PWA data
- IndexedDB records
- media or file cache
Session Management
Sessions and cookies should be managed carefully.
A session usually connects a browser user with server-side user data.
Browser has session ID
↓
Server maps session ID to user data
↓
User stays authenticated
For session cookies, use proper cookie flags.
res.cookie("sessionId", sessionId, {
httpOnly: true,
secure: true,
});
| Cookie Flag | Purpose |
|---|---|
HttpOnly | Helps prevent JavaScript from reading the cookie |
Secure | Sends the cookie only over HTTPS |
Important note:
Session cookies should usually be controlled from the server.
Do not depend only on client-side JavaScript for session security.
Summary
Client-side security means storing less sensitive data in the browser, protecting what must be stored, expiring tokens, validating integrity, respecting storage limits, and managing sessions safely.
Client storage is useful, but not fully trusted.
Remember it like this:
Client-side Security = Store Less + Encrypt + Expire + Verify + Limit + Secure Sessions
Or even simpler:
Server first.
Client only when needed.
Protect everything important.