I'm new to the MERN stack and am running into an issue with react-cookie. I am attempting to store a JWT token as a cookie named "acces_token" and use it across other routes. When I login/create and navigate the user to the "/Profile" route the cookie works exactly as expected but if I refresh the "/Profile" route at all, there is an empty "acces_token" cookie generated and its causing me issues. If I navigate away from the profile page the "/Profile" cookie is deleted and my root "/" cookie stays as desired. I originally assumed this is because the "/Profile" routes child routes but even when removing the children, I get the same result. Any useful docs or examples would be appreciated.
Profile.jsx
import Navbar from "../components/Navbar"
import testImg from "../assets/galleryImages/img1.jpg"
import "../stylesheets/profile.scss"
import { useEffect, useState } from "react"
import { useNavigate, Outlet, Link } from "react-router-dom"
import { useCookies } from "react-cookie"
import axios from "axios"
import { useGetUserID } from "../hooks/useGetUserID"
const profile = () => {
//Use cookies to check if a user is logged in
const [cookies, setCookies, removeCookies] = useCookies("access_token")
const [userInfo, setUserInfo] = useState({})
//useNavigate hook to redirect on logout
const navigate = useNavigate();
//Custome hook to get user id from local storage
const userID = useGetUserID();
//Logout function clears access token from cookies
//and userID from localstorge then redirects to home page
const logout = () => {
removeCookies("access_token")
window.localStorage.removeItem("userID")
navigate("/Login")
}
//Use Effect will load current user info
//ISSUE: Loads when user logins in and is navigated from login page but will not load when returning to login page.
useEffect(() => {
const fetchUser = async () => {
try {
const response = await axios.get(
`${import.meta.env.VITE_BASE_URI}/auth/profile/${userID}`,
{ headers: { auth: cookies.access_token } }
);
setUserInfo(response.data);
} catch (err) {
console.log(err);
}
}
fetchUser();
}, [])
return (
<div className="banner">
<Navbar />
<div className="profileContent container">
<div className="profileNav">
<img src={testImg} alt="Profile Image" />
<h3>{userInfo.fname} {userInfo.lname}</h3>
<ul>
<li><Link className="profileNavLinks" to="UserProfile">Profile</Link></li>
<li><Link className="profileNavLinks" to="Appointments">Appointments</Link></li>
<li><a className="profileNavLinks" onClick={logout}>Logout</a></li>
</ul>
</div>
<div className="profileInformation">
<Outlet />
</div>
</div>
</div>
)
}
export default profile
main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from "react-router-dom"
import { CookiesProvider } from 'react-cookie'
import Home from "./pages/home"
import Services from "./pages/services.jsx"
import About from "./pages/about.jsx"
import Gallery from "./pages/gallery.jsx"
import Vehicles from "./pages/vehicles.jsx"
import Login from "./pages/login.jsx"
import Schedule from './pages/schedule.jsx'
import Register from "./pages/register.jsx"
import Profile from "./pages/profile.jsx"
import Appointments from "./pages/appointments.jsx"
import UserProfile from "./pages/userProfile.jsx"
import ErrorPage from "./pages/error-page.jsx"
import "./stylesheets/main.scss"
const router = createBrowserRouter([
{
index: true,
path: "/",
element: <Home />,
errorElement: <ErrorPage />,
},
{
path: "/Services",
element: <Services />,
},
{
path: "/Gallery",
element: <Gallery />,
},
{
path: "/About",
element: <About />,
},
{
path: "/Vehicles",
element: <Vehicles />,
},
{
path: "/Login",
element: <Login />,
},
{
path: "/Register",
element: <Register />,
},
{
path: "/Profile",
element:<Profile />,
children: [
{
path: "UserProfile",
element:<UserProfile />,
},
{
path: "Appointments",
element:<Appointments />,
},
]
},
{
path: "/Schedule",
element: <Schedule />,
},
])
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<CookiesProvider>
<RouterProvider router={router} />
</CookiesProvider>
</React.StrictMode>,
)
login.jsx (This is where the cookie is created and routes to /Profile on successful login as expected)
import Navbar from "../components/Navbar"
import FormInput from "../components/FormInput"
import "../stylesheets/formPageStyles.scss"
import { useState } from "react"
import { useCookies } from "react-cookie"
import { useNavigate } from "react-router-dom"
import axios from "axios"
const Login = () => {
const [formValues, setFormValues] = useState({
email: "",
pwd:"",
})
const inputs = [
{
name: "email",
type: "email",
placeholder: "Email...",
label: "Email:",
pattern: /^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/,
required: true,
errormessage: "Please enter valid email address...",
},
{
name: "pwd",
type: "password",
placeholder: "Password...",
label: "Password:",
required: true,
errormessage: "Please enter a password...",
},
]
//Setting state for form values on each change of the value
const handleChange = (e) => {
setFormValues({...formValues, [e.target.name]: e.target.value})
}
const [errorMessage, setErrorMessage] = useState("");
//Used to set cookes when user logs in successfully
const [_, setCookies] = useCookies(["access_token"])
//useNavigate hook to navigate user after login
const navigate = useNavigate()
//Attempting to validate user and login
const onSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post(`${import.meta.env.VITE_BASE_URI}/auth/login`, { ...formValues });
if(!response.data.message){
setCookies("access_token", response.data.token, {path: '/'});
window.localStorage.setItem("userID", response.data.userID);
navigate("/Profile/UserInfo");
}else{
setErrorMessage(response.data.message);
}
} catch (err){
console.log(err);
}
}
//building form with formInput component
return (
<div className="banner">
<Navbar />
<div className="formPageContent">
<h1>Login</h1>
<form onSubmit={onSubmit}>
<span className="errorMessage">{errorMessage}</span>
{inputs.map((input, key) => (
<FormInput
{...input}
key={key}
value={formValues[input.name]}
onChange={handleChange} />
))}
<div className="formGroup">
<button type="submit" className="submitBtn">Login</button>
</div>
</form>
<p>Don't have an account? <a className="formLinks" href="Register">Create Account</a></p>
<p>Forgot Username? <a className="formLinks" href="">Recover Username</a></p>
<p>Forgot Password? <a className="formLinks" href="">Change Password</a></p>
</div>
</div>
)
}
export default Login
I have nowhere in my code that Im aware of that should be creating an access_token cookie at "/Profile". Again the "/Profile" cookie does not generate until you are logged in and refresh the profile page or route back to the profile page.