Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Store Credentials in Redux store is a good practice?

I'm trying to develop a React/Redux application for learning purposes and I'm wondering if what I've done so far is a good practice or is not recommended. The first thing that I had to deal with was handle the authorized requests. I have a restfull api Rails back end. This server respond to the login request appending in the headers parameters such as access-token. This access-token is valid just for the next request, that in turn, return a new token valid for the next one and so on.

I implemented this flow in this way: The store dispatch the action that perform the login request passing username and password. Then when the response is ready I store the credentials in the redux store. When I need to perform an authorized request I set those parameters in the header request. When I receive the response I update the credentials in the store with the new ones that I get from the response.

Here my code for more clearity:

import { combineReducers } from 'redux'
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

const initialState = {
  currentUser: {
    credentials: {},
    user: {}
  },
  test: {},
  users: []
}

export const SUBMIT_LOGIN = 'SUBMIT_LOGIN'
export const SET_USER = 'SET_USER'
export const TEST = 'TEST'
export const SET_USERS = 'SET_USERS'
export const SET_CREDENTIALS = 'SET_CREDENTIALS'

//actions
const submitLogin = () => (dispatch) => {
  return postLoginRequest()
    .then(response => {
      dispatch(setCredentials(
        response.headers.get('access-token'),
        response.headers.get('client'),
        response.headers.get('expiry'),
        response.headers.get('token-type'),
        response.headers.get('uid')
      ));
      return response
    })
    .then(response => {
      return response.json();
    })
    .then(
      (user) => dispatch(setUser(user.data)),
    );
}

const performRequest = (api) => (dispatch) => {
  return api()
    .then(response => {
      dispatch(setCredentials(
        response.headers.get('access-token'),
        response.headers.get('client'),
        response.headers.get('expiry'),
        response.headers.get('token-type'),
        response.headers.get('uid')
      ));
      return response
    })
    .then(response => {return response.json()})
    .then(json => {console.log(json)})
}

const setUsers = (users) => {
  return {
    type: SET_USERS,
    users
  }
}

const setUser = (user) => {
  return {
    type: SET_USER,
    user
  }
}

const setCredentials = (
  access_token,
  client,
  expiry,
  token_type,
  uid
) => {
  return {
    type: SET_CREDENTIALS,
    credentials: {
      'access-token': access_token,
      client,
      expiry,
      'token-type': token_type,
      uid
    }
  }
}

const currentUserInitialState = {
  credentials: {},
  user: {}
}

const currentUser = (state = currentUserInitialState, action) => {
  switch (action.type) {
    case SET_USER:
      return Object.assign({}, state, {user: action.user})
    case SET_CREDENTIALS:
      return Object.assign({}, state, {credentials: action.credentials})
    default:
      return state
  }
}

const rootReducer = combineReducers({
  currentUser,
  test
})

const getAuthorizedHeader = (store) => {
  const credentials = store.getState().currentUser.credentials
  const headers = new Headers(credentials)
  return headers
}

//store creation

const createStoreWithMiddleware = applyMiddleware(
  thunk
)(createStore);

const store = createStoreWithMiddleware(rootReducer);

const postLoginRequest = () => {
  return fetch('http://localhost:3000/auth/sign_in', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      email: '[email protected]',
      password: 'password',
    })
  })
}

const getUsers = () => {
  const autorizedHeader = getAuthorizedHeader(store)
  debugger
  return fetch('http://localhost:3000/users',
    {
      method: 'GET',
      headers : autorizedHeader
    }
  )
}


store.dispatch(submitLogin())

setTimeout(() => {
  console.log(store.dispatch(performRequest(getUsers)))
}, 2000)

I'm wondering if store sensible data in the store in a good practice and if not I'm open to any suggestions to develop this workflow in a better way.

I have also this parameter on my server

config.batch_request_buffer_throttle = 5.seconds

Sometimes it's necessary to make several requests to the API at the same time. In this case, each request in the batch will need to share the same auth token. This setting determines how far apart the requests can be while still using the same auth token.

In this way I could not dispatch the setCredentials action in my performRequest function if the token is still valid but I don't really have ideas how to check it.

Thanks

like image 863
TWONEKSONE Avatar asked Feb 12 '16 14:02

TWONEKSONE


People also ask

Should I store user in Redux?

If you're already using redux anyway: Yes. The user information is considered global application state and consumed by multiple components, so redux is a perfect fit.

What is the proper way to access Redux store?

The best way to access your store in a component is to use the connect() function, that creates a new component that wraps around your existing one.

Should I store all state in Redux?

Some users prefer to keep every single piece of data in Redux, to maintain a fully serializable and controlled version of their application at all times. Others prefer to keep non-critical or UI state, such as “is this dropdown currently open”, inside a component's internal state. Using local component state is fine.


1 Answers

No. It is not a good practise. If you wish to store user sessions better using cookie sessions to store JWT incase of React.js.

In case of react-native using react-native-keychain to store your passwords that too I would recommend as JWT token or Crypted text and not as plain text.

Your implementation mostly depends on your back end. If your using libraries like passport.js ( in case of node.js server) you use the crypt token to authorise requests. But whatever means you have to do auth don't store it in state plainly.

like image 161
Naveen Vignesh Avatar answered Sep 19 '22 11:09

Naveen Vignesh