Himanshu Chandola

Feb 20, 2025 • 3 min read

Secure vs. Non-Secure localStorage Handling in JavaScript/Typescript

How to Store Data in localStorage Securely Using Encryption

Secure vs. Non-Secure localStorage Handling in JavaScript/Typescript

localStorage is a simple and effective way to store key-value pairs in the browser. However, by default, data stored in localStorage is not encrypted, meaning anyone with access to the browser's developer tools can easily read it. This poses a security risk, especially when dealing with sensitive user data.

In this article, we'll compare two implementations of handling localStorage data:

  • A non-encrypted version, where data is stored as plain JSON.

  • An encrypted version, where data is securely stored using AES encryption via CryptoJS.

By the end of this article, you'll know how to securely store and retrieve data from localStorage using encryption.


1. Non-Encrypted localStorage Handling

The following implementation is a basic way to handle data in localStorage. While it's simple and effective, it has no security measures, meaning anyone with access to the browser can read the stored data.

// Set localStorage data
export const setLocalStorageData = (key: string, value: any) => {
  try {
    const localStorageValue = JSON.stringify(value);
    localStorage.setItem(key, localStorageValue);
  } catch (error) {}
};

// Get localStorage data
export const getLocalStorageData = (key: string, fallback: any) => {
  try {
    const localStorageValue = localStorage.getItem(key);
    return localStorageValue ? JSON.parse(localStorageValue) : fallback;
  } catch (error) {
    return fallback;
  }
};

// Clear localStorage data
export const clearLocalStorageData = (key: string) => {
  try {
    localStorage.removeItem(key);
  } catch (error) {}
};

🚨 Why is this insecure?

  • The data is stored in plain text, meaning anyone can inspect and retrieve it.

  • It offers no protection against data tampering.

  • If an attacker gains access to the localStorage, they can easily read sensitive information.

🔗 Check the full source code here: Non-Encrypted Gist


2. Encrypted localStorage Handling (AES Encryption)

To improve security, we can encrypt the data before storing it in localStorage. This way, even if someone accesses the localStorage, they will only see an unreadable encrypted string instead of sensitive data.

🔑 Using an Environment Variable for Encryption Key

To ensure security, we use an environment variable for the encryption secret key instead of hardcoding it in the application. This should be configured in the .env.local file:

NEXT_PUBLIC_LOCALSTORAGE_ENCRYPTION_SECRET_KEY=your_secret_key_here

⚠️ Note: In a production environment, never expose sensitive keys directly in client-side code.


🔐 Encrypted localStorage Handling

Here’s a secure implementation using AES encryption via CryptoJS:

import CryptoJS from "crypto-js";

// Set data in localStorage with encryption
export const setLocalStorageData = (key: string, value: any) => {
  if (typeof window !== "undefined") {
    try {
      const stringValue = JSON.stringify(value);
      const secretKey = process.env.NEXT_PUBLIC_LOCALSTORAGE_ENCRYPTION_SECRET_KEY || "";
      const encryptedValue = CryptoJS.AES.encrypt(stringValue, secretKey).toString();
      localStorage.setItem(key, encryptedValue);
    } catch (error) {
      console.error("Error setting localStorage data:", error);
    }
  }
};

// Get decrypted data from localStorage
export const getLocalStorageData = (key: string, fallback: any) => {
  if (typeof window !== "undefined") {
    try {
      const encryptedValue = localStorage.getItem(key);
      if (!encryptedValue) return fallback;
      const secretKey = process.env.NEXT_PUBLIC_LOCALSTORAGE_ENCRYPTION_SECRET_KEY || "";
      const bytes = CryptoJS.AES.decrypt(encryptedValue, secretKey);
      const decryptedValue = bytes.toString(CryptoJS.enc.Utf8);
      return decryptedValue ? JSON.parse(decryptedValue) : fallback;
    } catch (error) {
      console.error("Error getting localStorage data:", error);
      return fallback;
    }
  }
  return fallback;
};

// Clear specific data from localStorage
export const clearLocalStorageData = (key: string) => {
  try {
    localStorage.removeItem(key);
  } catch (error) {
    console.error("Error clearing localStorage data:", error);
  }
};

✅ Why is this secure?

  • Data is encrypted before being stored in localStorage, making it unreadable without the secret key.

  • AES encryption adds a layer of security that prevents direct access to the stored data.

  • Even if an attacker accesses localStorage, they will only see an encrypted string, not plain text.

  • Uses an environment variable for the encryption key, ensuring it’s not hardcoded in the codebase.

🔗 Check the full source code here: Encrypted Gist


Final Thoughts

Using localStorage is convenient, but security should always be a priority. If you’re storing non-sensitive data, a basic localStorage implementation might be sufficient. However, for user sessions, authentication tokens, or personal data, it's best to use encryption.

Join Himanshu on Peerlist!

Join amazing folks like Himanshu and thousands of other people in tech.

Create Profile

Join with Himanshu’s personal invite link.

0

6

1