Search code examples
node.jsreactjsnext.jsfetch-apinext.js13

Next js 13.4 get cookies from NodeJs API


Can you guys check my code, i have a Nextjs and Node api app, and i'm currently having a problem on getting the cookie from my api to my Next app, the signInUser api i made should return a generated jwt cookie but when i use it in my Next app it doesnt show in my devtools application-cookies, however when trying the api from postman or thunder client i see the jwt token in the cookies tab, what am I missing?

here is my backend Node api code for signin

const app = express();
app.use(cors());

 export const signInUser = async (
   req: express.Request,
   res: express.Response
   ) => {
  const { username, password } = req.body;

try {
let user = await getUserByEmail(username).select(
  "+authentication.password"
);

if (!user) {
  user = await getUserByUserName(username).select(
    "+authentication.password"
  );
}
if (!user) {
  const response: ResponseProps = {
    isError: true,
    message: "Invalid username or email",
  };
  res.status(400).json(response);
  return;
}
const passwordMatch = await bcrypt.compare(
  password,
  user.authentication.password
);

if (!passwordMatch) {
  const response: ResponseProps = {
    isError: true,
    message: "Invalid username/email or password",
  };
  res.status(400).json(response);
  return;
}
const response: ResponseProps = {
  isError: false,
  message: "Sign in successful",
  data: user,
};

this is my custom generateToken method that takes the express.Response and user.Id from signin api

generateToken(res, user.id);
res.status(200).json(response);
 } catch (error) {
 res.status(400).json(error);
    }
 };

 export const generateToken = (res: express.Response, userId: String) => {
   const token = jwt.sign({ userId }, process.env.JWT_SECRET, {
     expiresIn: "1d",
   });

   res.cookie("jwt", token, {
    httpOnly: true,
    secure: process.env.SERVER_ENVIRONMENT !== "development",
     sameSite: "strict",
    maxAge: 86400,
   });
  };

here is my frontend Next code for signin

 const handleSignIn = async (values: z.infer<typeof formSchema>) => {
   setIsLoading(true);
   try {
    const res = await axios.post(SIGNIN_URL, values);
  const data = res.data;
  if (data.isError === true) {
    setSignInError("Invalid username or password.");
  } else {
    router.push("/home");
    form.reset();
    setSignInError("");
    toast({
      duration: 5000,
      variant: "default",
      title: "Success!",
      description: "Welcome back! What's up?",
    });
  }
  setIsLoading(false);
} catch (error) {
  toast({
    duration: 5000,
    variant: "destructive",
    title: "Uh oh! Something went wrong.",
    description: "There was a problem with your request.",
  });
  setIsLoading(false);
}

};


Solution

  • the only thing I can think of is res.cookie might not set cookies for different domains. Postman does not enforce the same-origin policy or have the same security restrictions as browsers. cors is implemented by browser, which is why I guess it works in postman. if you set the cors in express with options

    import cors from "cors";
    
    const options: cors.CorsOptions = {
      allowedHeaders: [
        "Origin",
        "X-Requested-With",
        "Content-Type",
        "Accept",
        "X-Access-Token",
      ],
      credentials: true,
      methods: "GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE",
      // whatever port for next.js
      origin: "http://localhost:3000",
      preflightContinue: true,
    };
    const app = express();
    
    app.use(cors(options));