encryptionreact-nativereduxasyncstorage

React native persist and encrypt user token - Redux-persist-transform-encrypt error


It seems there is an issue using the encrypt option of redux-persist in react-native:

https://github.com/maxdeviant/redux-persist-transform-encrypt/issues/15

Can anyone help with any solution/workaround to use redux persist to encrypt and store a login token in react-native?

When I try to use the redux persist with the redux-persist-transform-encrypt i get Redux-persist-transform-encrypt: expected outbound state to be a string error

import { createStore, compose, applyMiddleware } from 'redux';
import ReduxThunk from 'redux-thunk';
import { persistStore, autoRehydrate } from 'redux-persist';
import { AsyncStorage } from 'react-native';
import createEncryptor from 'redux-persist-transform-encrypt';
import reducers from './reducers';


const store = createStore(
  reducers,
  {},
  compose(
    applyMiddleware(ReduxThunk),
    autoRehydrate(),
  ),
);

const encryptor = createEncryptor({
  secretKey: 'my-super-secret-key-999',
});


persistStore(
  store,
  {
    storage: AsyncStorage,
    whitelist: ['auth'],
    transforms: [encryptor],
  },
);
export default store;

My auth state is something like this:

const INITIAL_STATE = {
  user: null,
  token: ''
};

Is there any solution to use redux-persist-transform encrypt or the transform and other package to encrypt the token when using redux persist?


Solution

  • I found a solution using the customTransform instead of redux-persist-transform-encrypt:

    import { createStore, compose, applyMiddleware } from 'redux';
    import ReduxThunk from 'redux-thunk';
    import { persistStore, createTransform, autoRehydrate } from 'redux-persist';
    import { AsyncStorage } from 'react-native';
    import CryptoJS from 'crypto-js';
    import reducers from './reducers';
    
    
    const store = createStore(
      reducers,
      {},
      compose(
        applyMiddleware(ReduxThunk),
        autoRehydrate(),
      ),
    );
    
    const encrypt = createTransform(
      (inboundState, key) => {
        if (!inboundState) return inboundState;
        const cryptedText = CryptoJS.AES.encrypt(JSON.stringify(inboundState), 'secret key 123');
    
        return cryptedText.toString(); 
      },
      (outboundState, key) => {
        if (!outboundState) return outboundState;
        const bytes = CryptoJS.AES.decrypt(outboundState, 'secret key 123');
        const decrypted = bytes.toString(CryptoJS.enc.Utf8);
    
        return JSON.parse(decrypted);
      },
    );
    
    persistStore(
      store,
      {
        storage: AsyncStorage,
        whitelist: ['auth'], // <-- keys from state that should be persisted
        transforms: [encrypt],
      },
    );
    export default store;
    

    When using redux-persist initial state is triggered before rehydrating is finished so I had to apply this too:

    https://github.com/rt2zz/redux-persist/blob/master/docs/recipes.md#delay-render-until-rehydration-complete