I have run into the issue where I cannot set the cookie in the browser, due to the client being hosted at Netlify and server at Heroku. It worked fine on localhost, so it seems it has something to do with it being cross-domain now.
Having read multiple posts on this it seems like it might have to do with cors or how I'm setting the cookies to begin with.
I read somewhere that it might help adding secure: true
and sameSite: "none"
when setting the cookie, so I added them but it didn't help. I also have tried adding domain
into the cookie when setting it, but it also didn't help unfortunately.
I'm using Chrome and have changed the setting from blocking third party cookies with icognito to allow all cookies, as I have read that this might be an issue sometimes. However it did not yield any new results either.
I have also read that it might require a proxy for whatever reason or that it could be solved by hosting both client and server on Heroku. I would prefer not having to do any of these things if possible, but any ideas are welcome.
Server side with Node js (express) hosted on Heroku:
const express = require("express");
const app = express();
require("dotenv").config();
const cors = require("cors");
const mysql = require("mysql");
const jwt = require("jsonwebtoken");
const cookieParser = require("cookie-parser");
// port for heroku if needed
const PORT = 3001;
// app objects instantiated on creation of the express server
app.use(
cors({
origin: [
"https://examples.netlify.app",
"http://localhost:3000",
],
methods: ["GET", "POST", "DELETE"],
credentials: true,
})
);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
/*
* Handel user login
*/
app.post("/sign-in", (req, res) => {
const { email, password } = req.body;
sqlSelectAllUsers = "SELECT * FROM user_db WHERE email = ?";
db.query(sqlSelectAllUsers, [email], (err, user) => {
if (err) {
res.send({ err: err });
}
if (user && user.length > 0) {
// given the email check if the password is correct
bcrypt.compare(password, user[0].password, (err, compareUser) => {
if (compareUser) {
//req.session.email = user;
// create access token
const accessToken = createAccessToken(user[0]);
const refreshToken = createRefreshToken(user[0]);
// create cookie and store it in users browser
res.cookie("access-token", accessToken, {
maxAge: 1000 * 60 * 30, // 30 min
httpOnly: true, // hinder doing document.cookies as it will be httpOnly which will make it more safe
secure: true,
domain: "https://examples.netlify.app/",
sameSite: "none",
});
res.cookie("refresh-token", refreshToken, {
maxAge: 2.63e9, // approx 1 month
httpOnly: true,
secure: true,
domain: "https://examples.netlify.app/",
sameSite: "none",
});
// update refresh token in database
const sqlUpdateToken =
"UPDATE user_db SET refresh_token = ? WHERE email = ?";
db.query(
sqlUpdateToken,
[refreshToken, user[0].email],
(err, result) => {
if (err) {
res.send(err);
}
res.sendStatus(200);
}
);
} else {
res.send({ message: "Wrong email or password" });
}
});
} else {
res.send({ message: "Wrong email or password" });
}
});
});
app.listen(process.env.PORT || PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Client side with React hosted on Netlify:
export default function SignIn() {
const history = useHistory();
const handleSubmit = (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
// eslint-disable-next-line no-console
axios
.post(
"https://example.herokuapp.com/sign-in",
{
email: data.get("email"),
password: data.get("password"),
},
{ withCredentials: "true" }
)
.then((response) => {
//check if good response then give user a token for valid login
if (response.data === "OK") {
history.push("/");
history.go(0);
}
});
};
}