title: Persist React Cookie-based Authentication state
body: <p>I'm building an authentication flow using React-Router &amp; Redux where my backend returns a JWT in the form of a Session Cookie (with a Set-Cookie HTTP header) which the Frontend uses in order to make subsequent requests. (I'm not using localStorage as the general recommendation is to prefer a Cookie because of the risk of it being readable by JS in case of XSS)</p>
  
  <pre class="lang-html prettyprint-override"><code>// my App component
    const { isAuthenticated } = useSelector((state) =&gt; state.user);
  
            &lt;Container&gt;
              {!isAuthenticated ? (
                &lt;LoginForm /&gt;
              ) : (
                &lt;Switch&gt;
                  &lt;Route exact path="/" component={MessageList} /&gt;
                  &lt;Route path="/messages" component={MessageList} /&gt;
                  &lt;Route path="/login" component={LoginForm} /&gt;
                  &lt;Route path="/message/:id" component={MessageContainer} /&gt;
                &lt;/Switch&gt;
              )}
            &lt;/Container&gt;
  </code></pre>
  
  <pre class="lang-js prettyprint-override"><code>// the api requests themselves abstracted
  const login = (data) =&gt;
    axios
      .post("auth/login", data, { withCredentials: true })
      .then((response) =&gt; response.data);
  
  const fetchItems = (page, token) =&gt;
    axios(`message/list/page/${page}`, {
      withCredentials: true,
    }).then((response) =&gt; response.data);
  </code></pre>
  
  <pre class="lang-js prettyprint-override"><code>// actions
  function handleError(err) {
    return {
      type: "ERROR_OCCURED",
      payload: err,
    };
  }
  
  function shouldFetchMessages(state, page) {
    if (!state.message.all.length) {
      return true;
    } else if (state.message.isFetching) {
      return false;
    } else {
      return state.message.all;
    }
  }
  
  export let getMessages = (page = 1) =&gt; async (dispatch, getState) =&gt; {
    let err, response;
  
    dispatch(requestMessages(page));
    [err, response] = await to(api.fetchItems(page, getState().user.accessToken));
    if (err) {
      return handleError(err);
    }
    return dispatch(receiveMessages(response));
  };
  
  export function getMessagesIfNeeded(page) {
    return (dispatch, getState) =&gt; {
      if (shouldFetchMessages(getState(), page)) {
        return dispatch(getMessages(page));
      }
    };
  }
  </code></pre>
  
  <pre class="lang-js prettyprint-override"><code>// reducer
  // where would the localStorage isAuthenticated value be synced with the store?
  export default (state = defaultState, action) =&gt; {
    switch (action.type) {
      // skipped the other reducers for brevity
      case "ERROR_OCCURED":
        return {
          ...state,
          isAuthenticated: false, // this should be saved in the localStorage
        };
      default:
        return state;
    }
  };
  </code></pre>
  
  <p>I need to have a <code>BOOLEAN</code> which holds the 'state' of <code>isAuthenticated</code> so I can show the appropriate component. </p>
  
  <p>My main problem is that Redux state is of course not persisting across page refreshes.</p>
  
  <p>I thought of having a <code>localStorage</code> variable, (or a new <code>cookie</code>). (The Cookie that contains the JWT is <code>httpOnly</code> and from my understanding cannot be accessed by JavaScript). </p>
  
  <p>Questions: </p>
  
  <ul>
  <li>is this an established practice</li>
  <li>how would be JWT expiration be handled? (I guess I could set it to false if the HTTP request would fail with 401.)</li>
  <li>where would the localStorage variable be synchronized with the Redux state to avoid side-effects in my Reducers?</li>
  </ul>