Although you cannot do anything with the httpOnly cookie in the frontend, there definitely IS a way to handle frontend-sent httpOnly cookies and extract your JWT from that cookie, all in the backend of your MERN stack app.
As far as persisting the user and preventing the 'logout upon refresh' issue, you will have to create a useEffect hook that constantly checks whether the token exists or not - we'll get to that later.
First, I recommend using Cors in your backend:
const cors = require("cors");
app.use(
cors({
origin: ["http://...firstOrigin...", ...],
credentials: true,
})
);
Once that's ready to go, set the following options when creating your httpOnly cookie. Also, create a non-httpOnly cookie that tracks your httpOnly cookie with same expiration date and a boolean value instead if the JWT. This will allow you to use the 'universal-cookie' library and actually read the non-httpOnly cookie in the frontend:
res
.cookie("token", token, {
origin: "http://...firstOrigin..."
expires: // set desired expiration here
httpOnly: true,
secure: true,
sameSite: "none",
})
.cookie("checkToken", true, {
origin: "http://...firstOrigin..."
expires: // same as above
secure: true,
sameSite: "none",
})
Having created a 'checkToken' cookie that mimics our actual 'token', we can use it to set the state (useState hook) and persist the user if it exists and not expired, through the useEffect hook.
However, to send it correctly, we must specify a few things first. In this example, I will use axios to make such API call in the frontend.
Note that every API call's request header will contain our httpOnly cookie and it's content - we can confirm this by opening chrome dev tools' network tab, make the API call, then check the "Request Headers" for the "Cookie"...
const cookies = new Cookies();
const checkToken = cookies.get("checkToken");
const AuthUser = () => {
const [user, setUser] = useState(checkToken);
useEffect(() => {
async function checkToken() {
await axios
.post("http://...yourBackend.../authToken", {
withCredentials: true, // IMPORTANT!!!
})
.then((res) => {
// handle response - if successful, set the state...
// to persist the user
)}
.catch((err) => {
// handle error
)}
};
checkToken();
}, []);
// Implement your login behavior here
}
Once that's done, we can confirm that we're getting such token in the request body of our API call in the backend (wherever that's handled), log the cookie in the console to check for it, then store the cookie's value in a variable to enable verification of said cookie:
app.post(".../authToken", (req, res) => {
// Get all cookies from request headers
const { cookie } = req.headers;
// Check to see if we got our cookies
console.log(cookie);
// Handle this as you please
if (cookie == undefined) return;
const token = cookie.split("token=")[1].split(";")[0]; // Yep, it's a string
console.log(token); // Check to see if we stored our cookie's JWT
// Some middleware:
jwt.verify(token, process.env.TOKEN, (err, user) => {
// if success upon verification,
// issue new 'token' and 'checkToken'
});
});
Done.
Please note that this a general implementation and serves as only a guide to understanding the functionality of httpOnly cookies. OP never provided original code to go off of.
I hope this helps. Godspeed.