Express res.cookie not setting cookie on client side - node.js

I am trying to configure my JWT through http-only cookies
const signIn = async (req, res) => {
const { email } = req.body;
try {
const user = await User.findOne({ email });
const access_token = jwt.sign({ id: user._id }, jwtSecret, {
expiresIn: token_expiry_time,
});
const refresh_token = jwt.sign({ id: user._id }, jwtRefreshSecret, {
expiresIn: refresh_token_expiry_time,
});
res.cookie('access_token', access_token, { httpOnly: true });
res.cookie('refresh_token', refresh_token, { httpOnly: true });
return res.status(200).json({
status: true,
data: {
user: {
id: user._id,
},
},
});
} catch (err) {
Server.serverError(res, err);
}
};
but at the client-side it refuses to set the cookie in the browser, it returns the error "cannot set cookie because same-site is not 'None' ", After setting sameSite:'None' on the server side, it then gave the error "same-site set to 'None' needs to have a 'Secure' field", I then set secure:true on the backend but it doesn't work because I am not using https for development.
client-side code
const onSubmit = (cred) => {
setLoading(true);
restAPI
.post('auth/signin', cred)
.then(({ data }) => {
setLoading(false);
setError(false);
console.log(data.data);
})
.catch((err) => {
setLoading(false);
setError({
status: true,
message: err.response.data.message,
});
});
};
how can I solve this?

Related

Set Cookie not working (nextJs + express)

I'm trying to set the cookie from my express backend to my nextjs front end using the response.setHeader, but it's not working, I get my json response but no cookies are set, I used postman to make some tests and in postman it did set the cookies as it should be.
NextJs version is 13.0.2, express version is 4.18.2 and cookie version is 0.5.0
My express server:
export const loginUser = async (req: Request, res: Response) => {
const { email, password } = req.body;
//limpa os cookies
res.clearCookie("accessToken", { httpOnly: true });
if (email !== "" && password !== "") {
try {
const foundUser: any = await prisma.users.findFirst({
where: {
email,
password,
},
});
try {
const accessToken = jwt.sign(
{ id: foundUser.id, email },
"dspaojdspoadsaodksa",
{
expiresIn: "10s",
}
);
const refreshToken = jwt.sign(
{ id: foundUser.id, email },
"dsaoindsadmnsaosda",
{
expiresIn: "50s",
}
);
const savedRefresh = await prisma.refresh_token.upsert({
where: {
users_id: foundUser.id,
},
update: {
access_token: accessToken,
refresh_tk: refreshToken,
users_id: foundUser.id,
},
create: {
access_expires_in: "",
refresh_expires_in: "",
access_token: accessToken,
refresh_tk: refreshToken,
users_id: foundUser.id,
},
});
res.setHeader(
"Set-Cookie",
cookie.serialize("accessToken", accessToken, {
maxAge: 1000 * 60 * 15, //15 minutes
httpOnly: true, // The cookie only accessible by the web server
})
);
res.json({ accessToken, user: { email }, ok: true });
} catch (error) {
console.log("refresh cant be created");
res.send({ message: "refresh cant be created" });
}
} catch (error) {
res.send({ message: "user not found" });
}
} else {
res.json({ message: "token creation failed" });
}
};
My nextJs front-end:
const handleLogin = async (event: React.SyntheticEvent) => {
event.preventDefault();
const email = (event?.target as any).email.value;
const password = (event?.target as any).password.value;
if (email === "" || password === "") {
setError(true);
return;
}
const data = {
email,
password,
};
const resp = await fetch("http://localhost:5000/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
const userData = await resp.json();
console.log(userData);
};

nodejs cookie does not save on browser storage

I am building a nodejs application
I want to save cookies using nodejs
it send the cookie to the browser
but it does not save on the browser storage
export const signin = async (req, res, next) => {
try {
const user = await User.findOne({
$or: [{ phone: req.body.phone }, { username: req.body.username }],
});
if (!user) return res.status(401).json({ msg: "Wrong Credentials" });
const isCorrect = bcrypt.compareSync(req.body.password, user.password); // true
if (!isCorrect) return res.status(401).json({ msg: "Wrong Credentials" });
const token = jwt.sign({ id: user._id, role: user.role }, process.env.JWT);
const { password, ...others } = user._doc;
res
.cookie("access_token", token, {
httpOnly: false,
secure: false,
maxAge: 60 * 60 * 24 * 7,
})
.status(200)
.json(others);
} catch (error) {
next(error);
}
};
Frontend
const get = path => {
const new_url = `${BASE_URL}${path}`;
return axios.get(new_url || {}, {
withCredentials: true,
credentials: "include",
});
};

Set-Cookie not sended on HTTP response header

i´m creating a Authentication page with React and Express. I'm using JWT too.
I´ve made this route in the back:
server.js
...
app.use(
cookieSession({
name: "prode_session",
secret: "MIOURI_PRODE_SECRET", //add to .env variable
httpOnly: false,
})
);
app.use(cors());
...
auth.routes.js
app.post("/signin", controller.signin);
user.routes.js
app.get(
"/user",
[authJwt.verifyToken],
(req, res) => res.send(true)
)
auth.controller.js
exports.signin = async (req, res) => {
const user = await Users.findOne({
where: { email: req.body.email },
});
try {
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
const passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({
message: "Invalid Password!",
});
}
const token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 84000, //24hours
});
req.session.token = token;
console.log(req.session);
return res.status(200).send({
isLogged: true,
id: user.id,
email: user.email,
suscripcion: user.suscripcion,
preference_id: user.preference_id,
token,
});
} catch (error) {
console.log(error);
}
};
authJWT.js
verifyToken = async (req, res, next) => {
let token = req.session.token;
console.log(`THIS IS THE TOKEN: ${token}`);
if (!token) {
return res.status(403).send({
message: "No token provided",
});
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
console.log(err);
return res.status(401).send({
message: "Unauthorized!",
});
}
req.id = decoded.id;
next();
});
};
const authJwt = { verifyToken };
module.exports = authJwt;
When I test this with POSTMAN, it works Ok, I mean, if first I try to make the GET request, the response is "No token provided", but if I signin first, generate the token and then make the GET request, I get true.
The problem is when I try to implement this in the front.
I have this Login component in React in which I make a POST request with the credentials:
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await fetch("http://localhost:3000/signin", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
body: JSON.stringify({
email,
password,
}),
});
const data = await response.json();
console.log(data);
if (data.isLogged && data.suscripcion === true && data.token) {
await tokenAvailable()
//navigate(`/masthead/${email}&${data.isLogged}&${data.id}`);
} else if (data.isLogged && data.suscripcion === false) {
navigate("/suscripcion", {
state: { preference_id: data.preference_id },
});
} else {
window.alert("Invalid Login");
}
} catch (error) {
console.log(error);
}
};
async function tokenAvailable() {
const user = await fetch("http://localhost:3000/user", {
method: "GET",
mode: "cors",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
});
const response = await user.json();
setUser(await response);
console.log(await response);
return response;
}
When I make the POST, the GET request is executed (tokenAvailable function) after receiving the response, but I receive "No token Provided" while I expect to receive "true" as in Postman.
From what I debug, the authJWT.js file, is not receiving nothing from the req.session.token.
When I compare the headers from postman and the browser, in postan the SET-cookie key appears, but in the browser not.
postman:
browser:
I need some help here. I´ve been strugling with this for almost 3 days.
I found a solution for this. Apparently, the HttpOnly Cookie approach works if the React app and the back-end server hosted in same domain. So we need to use http-proxy-middleware for local development.
I´ve tried to install the http-proxy-middleware but a lot of errors came, so I decided to store de JWT in the localstorage.

Cookie token sent by server but not stored in browser

I have this code in node js API :
const jwt = require("jsonwebtoken");
generateToken = (user, res) => {
const token = jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, {
expiresIn: "1800s",
});
res
.cookie("token", token, {
httpOnly: true,
})
.status(200)
.json({ message: "Logged in successfully 😊 👌" });
};
module.exports = generateToken;
I have this code in Next js project :
const onSubmitLogin = (data) => {
axios
.post(
`http://localhost:8000/login`,
{
email: data.email,
password: data.password,
},
{
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
}
)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
};
If I use Postman, i get the cookie with the token.
But, when I use the browser I dont get the cookie stored in cookies.
I tried to add withCredentials: true, in axios request but nothing changes.
However, I get the message "Logged in successfully 😊 👌" in the browser's console

My cookie does not set in my browser, How can I fixed?

I've working with jwt and cookies I don't why my cookie does not set in my browser.
If I do this in postman works properly, create cookie and looks well, but when I do this in my browser with my react form, cookie does not set.
Please any advice
This my frontend code
const onSubmit = useCallback(async (e) => {
e.preventDefault()
setStatus('pending')
setError(null)
const credentials = {
email: values.email,
password: values.password
}
console.log(credentials)
try {
const res = await API.post(LOGIN_API, credentials)
console.log(res.data)
if (res.data.success) {
setStatus('success')
navigate('/')
} else {
setStatus('error')
}
} catch (err) {
setError(error)
}
}, [values, error, navigate])
my backend
const login = async (req, res) => {
const text = 'SELECT user_id, password, email FROM user_account WHERE email=$1;'
const values = [req.body.email]
try {
const response = await client.query(text, values)
const match = await bcrypt.checkPassword(req.body.password, response.rows[0].password)
if (match) {
res.cookie("access_token", jwt.sign({ id: response.rows[0].user_id }, jwtSecret), { httpOnly: true })
res.status(200).json({ success: true, message: "Logged in successfully" })
} else {
res.status(401).json({ success: false, message: "Credentials are not valid" })
}
} catch (err) {
console.log(err.stack)
}
}
And then here my axios instance
import axios from 'axios'
export default axios.create({
baseURL: process.env.REACT_APP_BASE_API_URL
})
Cookies can only be set if you load a resource by a browser, no through JavaScript. There is no way to set httponly cookie this way.
Usually jwt tokens are stored in localStorage

Resources