The token for my react application is stored in the AuthContext
Provider and whenever the user is logged, the token is set using the setToken()
function.
AuthContext.js
import { useContext, useState, createContext, useMemo } from "react";
import {createAxiosInstance} from '../services/axiosInstance';
import { useNavigate } from "react-router-dom";
const AuthContext = createContext();
const AuthProvider = ({children}) => {
const [token, setToken] = useState(null);
// creates a new instance of axios Instance when the token is changed
const axiosInstance = useMemo(() => createAxiosInstance(token), [token]);
// create the login and signup functions here
const login = (email, password) => {
const data = {"email": email, "password": password};
console.log("Logging the user in");
const response = axiosInstance.post('/auth', data);
return new Promise((resolve, reject)=>{
response.then((responseData) => {
const {accessToken, message} = responseData.data;
setToken(accessToken);
return resolve(message);
})
.catch((err)=>{
return reject("Wrong email or password");
})
})
}
return (
<AuthContext.Provider value={{token,setToken, axiosInstance, login}}>
{children}
</AuthContext.Provider>
);
}
const useAuth = () => {
const context = useContext(AuthContext);
if(context === undefined){
throw new Error("The Context must be used under the AuthContextProvider");
}
return context;
}
export {AuthProvider as default, useAuth}
Inorder to implement protected routes in my application, I wrapped this component around all the routes that I wanted to be protected
import { jwtDecode } from "jwt-decode"
import { useAuth } from "../contexts/AuthProvider"
import { Navigate, Outlet } from "react-router-dom";
const ProtectedRoutes = ({ children }) => {
const { token, setToken, axiosInstance } = useAuth();
// if there is no token, send the user to the authentication route
if (!token) {
return <Navigate to='/users/authenticate' />
}
try {
// get the expiry time from the token
const { exp } = jwtDecode(token);
const expired = (Date.now() >= exp * 1000);
if (expired) {
axiosInstance.post('/auth/refresh') // if the token has expired, try to get a new token
.then((response) => {
const { accessToken } = response.data;
setToken(accessToken)
return <Outlet />
})
.catch((err) => { // if the user has no token stored in their cookies, then send them to login page
return <Navigate to="/users/authenticate" />
})
}
else{
return <Outlet /> // if the token has not expired, continue
}
}
catch (err) {
return <Navigate to='/users/authenticate' />
}
}
export default ProtectedRoutes;
But whenever I refresh the page, the token is set to null and protected routes logs me out.
How can I save the access Token other than storing it in localStorage or sessionStorage as I heard that those methods are not safe to attacks.