Javascript – When using Redux/Redux-Saga – should JWTs be set in the action creators/sagas

authenticationjavascriptjwtreduxredux-saga

Almost every blog post I've encountered around generic auth handling using JWTs in a React/Redux/Saga application does the same thing, which is to store the JWT in local storage, in the action/saga.

For example:

Example A (redux-saga):

function* authorize({ payload: { login, password } }) {
  const options = {
    body: JSON.stringify({ login, password }),
    method: 'POST',
    headers: { 'Content-Type': 'application/json' }
  };

  try {
    const { token } = yield call(fetchJSON, '/login', options);
    yield put({ type: AUTH_SUCCESS, payload: token });
    localStorage.setItem('token', token);
  } catch (error) {
    let message;
    switch (error.status) {
      case 500: message = 'Internal Server Error'; break;
      case 401: message = 'Invalid credentials'; break;
      default: message = 'Something went wrong';
    }
    yield put({ type: AUTH_FAILURE, payload: message });
    localStorage.removeItem('token');
  }
}

function* Saga() {
  yield takeLatest(AUTH_REQUEST, authorize);
}

Example B (redux):

function login(username, password) {
    const requestOptions = {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password })
    };

    return fetch(`${config.apiUrl}/users/authenticate`, requestOptions)
        .then(handleResponse)
        .then(user => {
            // login successful if there's a jwt token in the response
            if (user.token) {
                // store user details and jwt token in local storage to keep user logged in between page refreshes
                localStorage.setItem('user', JSON.stringify(user));
            }

            return user;
        });
}

function logout() {
    // remove user from local storage to log user out
    localStorage.removeItem('user');
}

Now – storing JWTs in local storage aside – what concerns me – is the setting of state inside of the action creator/saga – rather than in a reducer.

My understanding is that action creators/sagas should be used just to determine the data to be used – and it is up to the reducers to actual store/persist the data.

Now of course – at its initial state, redux won't persist data. However, you can use a redux middleware like redux-persist to persist it to local storage (and there are other redux-persist middlewares to persist data to other places). Point here is – redux is the state management.

Why then – does everybody seem to just sidestep using redux as your application state when it comes to authentication?

Best Answer

I will do a guess from different sources.

  1. I heard "security is not a crosscutting concern" I would put authentication in it. It can not be separated from the program although not included in the model and then pressed in when needed.
  2. Whether you are authenticated is not part of your model in a way that you have two objects, one authenticated and one not authenticated at the same time.

Thus, you try to push authentication as far away from the other logic. You put it in a layer between communication and model. That layer is so thin that you do not give extra space to it in an example as this layer may not evolve or evolve in unforeseen ways in programs building on the example. Besides, there are only two places to handle that use case.

An other one is that in an example, you like to go for simplicity instead of perfection.

PS: An answer like this usually leads to better answers coming. Good luck!

Related Topic