Humor
Humor

Reputation: 1

Next.JS Cookie Not Received By Server On Deployment

I am attempting to create a personal website/blog and have created a React Frontend using Next.JS (deployed on vercel) and I have attempted to create an Express API/backend which manages a connection to my MongoDB instance using mongoose (deployed on glitch.com).

I did it this way instead of using NextJS as my backend as a good learning experience because from my understanding your frontend and backend won't always be conjoined.

I am still just learning web development and after some research I decided to use JSON Web Tokens and bcrypt and some custom authorization middleware to authorize the user and decrypt their credentials.

When I am running both my NextJS instance and Express server on my localhost, I simply assign the servers to ports 3000 and 5000 and hard coded the URI endpoints into my NextJS frontend using the javascript Fetch API. Everything works great when running off my local machine.

I have a login function that properly creates a browser cookie and stores it for the frontend domain:

export default function BlogLogin() {
    //function for logging in user and generating token
    async function loginUser(formData) {
        "use server";
        try {
            console.log("fetching");
            const response = await fetch(
                `[glitch_url].glitch.com/api/users/login`,
                {
                    cache: "no-store",
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                    },
                    credentials: "include",
                    body: JSON.stringify(Object.fromEntries(formData)),
                }
            );
            const newCookies = setCookie.parse(response, { map: true });
            cookies().set(
                newCookies.access_token.name,
                newCookies.access_token.value,
                {
                    sameSite: "none",
                    secure: true,
                    httpOnly: true,
                    path: "/",
                }
            );
            console.log("fetched");
        } catch (err) {
            console.log(err);
        }
        redirect("https://www.[mysite].me/blog/admin");
    }

Here is the function for the POST request at that URI

exports.loginPost = async (req, res) => {
    const validResult = validationResult(req);
    if (validResult.isEmpty()) {
        try {
            const user = await User.findOne({
                username: req.body.username,
            });

            bcrypt.compare(
                req.body.password,
                user.password,
                (error, response) => {
                    if (error) {
                        console.log(error);
                    }
                    if (response === false) {
                        res.sendStatus(401);
                    }
                    if (response === true) {
                        jwt.sign(
                            user.toJSON(),
                            process.env.SECRETKEY,
                            (jwtErr, token) => {
                                if (jwtErr) {
                                    console.log(jwtErr);
                                } else {
                                    res.cookie("access_token", token, {
                                        httpOnly: true,
                                        sameSite: "None",
                                    }).sendStatus(200);
                                }
                            }
                        );
                    }
                }
            );
        } catch (userErr) {
            console.log(userErr);
        }
    } else {
        res.send({ error: validResult.array() });
    }
};

That properly saves the cookie to the browser: saved cookie in browser

And then here is my authorization middleware which I call before accessing a protected page:

function authUser() {
    return async function (req, res, next) {
        if (!req.cookies || !req.cookies.access_token) {
            console.error("No cookies");
            res.sendStatus(403, "No cookies");
        } else {
            jwt.verify(
                req.cookies.access_token,
                process.env.SECRETKEY,
                async (err, decoded) => {
                    if (err) {
                        console.error(err);
                        res.sendStatus(500);
                    } else {
                        try {
                            const user = await User.findById(decoded._id);
                            res.locals.user = user;
                        } catch (error) {
                            console.error(error);
                            res.sendStatus(403, "Token user not found");
                        }
                        console.log("User authenticated");
                        next();
                    }
                }
            );
        }
    };
}

However, once I deployed my backend to glitch, I noticed that my "authUser" function was no longer receiving cookies, as req.cookies was null.

I went into dev tools and even noticed that my request's didn't seem to have the cookies either: request image

I've read that there can be issues with cookies across different domains, but I have enabled CORS middleware on my express app with these settings:

const corsOptions = {
    origin: true,
    credentials: true,
};

app.use(cors(corsOptions));

Obviously some of this code isn't great but I was really happy that I was able to get it working locally. If anyone can offer assistance I would be most grateful.

Upvotes: 0

Views: 172

Answers (1)

Ilya Dobatovkin
Ilya Dobatovkin

Reputation: 1

Try setting the domain from which the request is coming in the origin field of corsOptions:

const corsOptions = {
  origin: 'https://example.com',
  credentials: true
}

Upvotes: 0

Related Questions