hackysack
hackysack

Reputation: 17

HttpOnly cookie appears in response header but is not being saved to the browser

I recently built a simple real-time chat application with Nextjs on the frontend and Express on the backend. The frontend is deployed on vercel while the backend is deployed on heroku. When a user logs into the app, the backend generates a jwt token which is then sent via an HttpOnly cookie back to the frontend. Here is the code for said response:

 const authenticate = async (req, res, next) => {
  userService
    .authenticate(req)
    .then((user) => {
      const { token, ...userInfo } = user;
      res
        .setHeader(
          "Set-Cookie",
          cookie.serialize("token", token, {
            httpOnly: true,
            secure: process.env.NODE_ENV !== "development",
            maxAge: 60 * 60 * 24,
            sameSite: "none",
            path: "/",
          })
        )
        .status(200)
        .json(userInfo);
    })
    .catch(next);
};

After authentication, each subsequent request to the backend is supposed to send the token to ensure the user is logged in. For example, this is the request sent to the server to get a chat between the logged in user and another user.

const getChat = async (id) => {
  const identification = id;
  const response = await axios.get(
    `<SERVER_URL>/chats/chat/${identification}`,
    { withCredentials: true }
  );

  return response;
};

In development when on localhost:3000 for the frontend and localhost:4000 for the backend, everything works fine. However, when I deployed the frontend to vercel and the backend to heroku, the browser simply refuses to save the cookie! The jwt token appears in the response header after sending the authentication request, but it isn't saved to the browser. I have tried absolutely everything I can think of, including changing the cookie parameters, but I can't get it to work. I am pretty sure I have cors properly configured on the backend as well, along with the cookie-parser module:


const cors = require("cors");
const cookieParser = require("cookie-parser");

app.use(
  cors({
    origin: "<CLIENT_URL>",
    credentials: true,
  })

app.use(cookieParser());

Thanks for taking the time to read this, any help would be greatly appreciated! And my apologies if I have not elaborated enough, this is my first post here and I'm still trying to learn the proper etiquette of the site!

Upvotes: 0

Views: 1728

Answers (1)

Paiman Rasoli
Paiman Rasoli

Reputation: 1214

HttpOnly can not read or write on client-side but when the first HttpOnly send through a request other request on the same origin can access the coockies in backend but you should request in Next.js like this. Next.js using fetch :

        const req = await fetch("http://localhost:7000/api/auth/login", {
      method: "POST",
      credentials: "include",
      headers: {
        "Content-Type": "application/json",
        "Access-Control-Allow-Credentials": true,
      },
      body: JSON.stringify({
        email: formData.get("email"),
        password: formData.get("password"),
      }),
    });
    const data = await req.json();

then in backend you can read the coockie through coockie-parser server.js:

const cookieParser = require("cookie-parser");
app.use(coockieParser());
route.post('/login',(req,res) => {
  if(user){
       res
  .cookie("access_token", newToken, {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production" ? true : false,
  })
  .status(200)
  .json({ ok: true, payload: data });
 }
})

Now you can read this cookie in other routes but sure about the expiration time.

Upvotes: 0

Related Questions