0

In my react/redux app, i have a problem where the app doesn't persist login after refresh. I'm using JWT token for my authentication. Below is my code for the auth actions file named auth.js and my auth reducers file named auth.js as well.

If there is a way i could make all my private routes check for the token and makes sure that i'm always logged in after refresh, kindly advice.

My action

import axios from "axios";
import { setAlert } from "./alert";
import {
  SIGNUP_SUCCESS,
  SIGNUP_FAIL,
  LOGIN_SUCCESS,
  LOGIN_FAIL,
  LOGOUT,
} from "./types";

export const login = (email, password) => async (dispatch) => {
  const config = {
    headers: {
      "Content-Type": "application/json",
    },
  };

  const body = JSON.stringify({ email, password });

  try {
    const res = await axios.post(
      "http://localhost:8000/api/token/",
      body,
      config
    );

    dispatch({
      type: LOGIN_SUCCESS,
      payload: res.data,
    });

    dispatch(setAlert("Authenticated successfully", "success"));
  } catch (err) {
    dispatch({
      type: LOGIN_FAIL,
    });

    dispatch(setAlert("Error Authenticating", "error"));
  }
};

My reducer

import {
    LOGIN_SUCCESS,
} from '../actions/types'

const initialState = {
    token: localStorage.getItem("token"),
    isAuthenticated: null,
    loading: false
}

export default function(state = initialState, action) {
    const { type, payload } = action

    switch (type) {
      case LOGIN_SUCCESS:
        localStorage.setItem("token", payload.access);
        return {
          ...state,
          isAuthenticated: true,
          loading: false,
          token: payload.access,
        };
}

My index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from "react-redux";
import store from "./store";
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';


ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById("root")
);

Edit: I have been adviced localStorage is not safe, if cookies is a safer alternative. Kindly assist with the solution implementation.

Shadow Walker
  • 979
  • 5
  • 27
  • 51

1 Answers1

0

While you're importing the token into Redux, isAuthenticated is still false, so I assume your application is checking for isAuthenticated being true and finding its not.

You would need to attempt to perform an action in the componentDidMount call of <App /> to check to see if there is a usable token and if the server recognizes it as valid. This is because simply having a token doesn't confirm it's a valid token and that the user is authenticated.

For if that call returns successfully, create a new action type called LOGIN_RETURNING or such that sets isAuthenticated to true, then your routes will now recognize you as logged in.

For if that call returns with an error, I'd run a LOGOUT action that sets isAuthenticated: false and token: undefined (or null).

Edit: Additionally, I'd caution against using localStorage for your JWTs as localStorage can be attacked via XSS. See Is it safe to store a jwt in localStorage with reactjs? for more info.