Secure Redux State in React
Securing Redux in React is essential to protect application state from exposure, tampering, and unauthorized access. This article explains the best practices for securing your Redux store, including restricting Redux DevTools in production, sanitizing sensitive data, encrypting persisted state, and preventing unauthorized state modifications.
1. Disable Redux DevTools in Production
Redux DevTools is an excellent tool for debugging during development, but leaving it enabled in production allows anyone to inspect your application’s state, view dispatched actions, and even travel back in time to manipulate state.
To secure your store, conditionally configure the DevTools extension so it is only available in development environments.
import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './rootReducer';
const store = configureStore({
reducer: rootReducer,
devTools: process.env.NODE_ENV !== 'production',
});2. Sanitize Sensitive Actions and State
If you must keep Redux DevTools enabled for certain staging or
debugging environments, you should sanitize sensitive data to prevent it
from being logged. You can use the stateSanitizer and
actionSanitizer options to mask sensitive fields like
passwords, tokens, or personal information.
const devToolsConfig = {
actionSanitizer: (action) =>
action.type === 'LOGIN_SUCCESS' && action.payload
? { ...action, payload: { ...action.payload, token: '<<TOKEN_MASKED>>' } }
: action,
stateSanitizer: (state) =>
state.auth && state.auth.token
? { ...state, auth: { ...state.auth, token: '<<TOKEN_MASKED>>' } }
: state,
};
const store = configureStore({
reducer: rootReducer,
devTools: process.env.NODE_ENV !== 'production' ? devToolsConfig : false,
});3. Encrypt Persisted Redux State
If your application uses libraries like redux-persist to
save state to localStorage or sessionStorage,
that data is stored in plain text. Anyone with physical access to the
device or malicious scripts (XSS) can read this data.
To secure persisted data, use an encryption transformer such as
redux-persist-transform-encrypt to encrypt the state before
it is written to storage.
import { persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import { createEncryptor } from 'redux-persist-transform-encrypt';
const encryptor = createEncryptor({
secretKey: process.env.REACT_APP_PERSIST_KEY,
onError: function (error) {
console.error('Encryption failed', error);
},
});
const persistConfig = {
key: 'root',
storage,
transforms: [encryptor],
};
const persistedReducer = persistReducer(persistConfig, rootReducer);4. Avoid Storing Highly Sensitive Information
The most effective security measure is to avoid storing highly sensitive information in the Redux store entirely. JSON Web Tokens (JWTs), passwords, credit card details, and personal identification info should ideally be handled via secure memory variables, HTTP-only cookies, or ephemeral state that is cleared immediately after use.
If a token must be stored, prefer short-lived access tokens over long-lived refresh tokens in the Redux state.
5. Enforce Immutability to Prevent State Tampering
To prevent malicious scripts or accidental bugs from directly mutating your Redux state from outside the normal dispatch flow, enforce strict immutability.
Using Redux Toolkit ensures immutability by default
because it uses the Immer library under the hood. If you are using
vanilla Redux, integrate middleware like
redux-immutable-state-invariant during development to catch
direct mutations early.