Reputation: 983
I am developing a fullstack app using React & Node.
The following is the home screen.
After a user logs in, the name of the user is displayed in the navbar and the response from the server (including the JWT) is saved in the local storage as shown in the following pictures:
Now, when I refresh the page the user is logged out. This should not happen because I am sending the token on every request header using axios global defaults as shown in the code snippet below:
frontend/src/App.js
import React from "react";
import { Container } from "react-bootstrap";
import Header from "./components/Header";
import Footer from "./components/Footer";
import Products from "./components/Products";
import { Route, Switch } from "react-router-dom";
import SingleProductView from "./components/SingleProductView";
import Cart from "./components/Cart";
import LoginForm from "./components/LoginForm";
import RegisterForm from "./components/RegisterForm";
import Profile from "./components/Profile";
import Shipping from "./components/Shipping";
import PaymentMethod from "./components/PaymentMethod";
import PlaceOrder from "./components/PlaceOrder";
import axios from "axios";
const {token} = localStorage.getItem("loggedInUser");
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
const App = () => {
return (
<>
<Header />
<main className="py-3">
<Container>
<Switch>
<Route path="/placeorder" component={PlaceOrder} />
<Route path="/payment" component={PaymentMethod} />
<Route path="/shipping" component={Shipping} />
<Route path="/profile" component={Profile} />
<Route path="/register" component={RegisterForm} />
<Route path="/login" component={LoginForm} />
<Route path="/product/:id" component={SingleProductView} />
<Route path="/cart/:id?" component={Cart} />
<Route path="/" component={Products} exact />
</Switch>
</Container>
</main>
<Footer />
</>
);
};
export default App;
What am I doing wrong? I want the user to stay logged in even after page refresh.
Upvotes: 2
Views: 3453
Reputation: 19813
Axios will lose its custom (provided by you) default headers settings after page is refreshed.
So, you need to set it again after page refresh (i.e. at App Start). You can do it in a component which always gets mounted before other components do:
In most cases, App component would be the perfect place for that:
// App.jsx
useEffect(() => {
const { token } = localStorage.getItem("loggedInUser");
if (token) {
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
}
}, [])
Assuming, you are setting the Token for the first time in localStorage after the Authentication is successful. E.g. in Login component.
Another option could be to write a Request Interceptor for Axios and check if this header exists or not; if not, then set it back from localstorage and let the request proceed.
Using Request Interceptor:
axios.interceptors.request.use(
function (config) {
if (!config.headers.Authorization) {
const { token } = localStorage.getItem('loggedInUser')
if (token) {
axios.defaults.headers.common['Authorization'] = `Bearer ${token}` // this will be used in next requests
config.headers.Authorization = `Bearer ${token}` // this is for current request
}
}
return config
},
function (error) {
return Promise.reject(error)
}
)
Edit: You are passing token to each AsyncThunkAction. So, all you need to do is initialize the redux state properly. So, in the loginSlice:
function getToken() {
const { token } = localStorage.getItem("loggedInUser");
if (token) {
return { token };
}
return null;
}
const initialState = {
status: "idle",
user: getToken(),
error: null,
};
Upvotes: 2