'is there a way to know why cookie does not get sent to the server
please, I am working on a Nodejs REST api with sign-up and log-in functionality,
- when a user logs in, they get an accessToken.
- secondly, A cookie is saved containing
refreshTokento enable the user make request to the/refreshendpoint for a new accessToken.
here is my problem; when a user logs in, I can see the cookie, but after subsequent requests to other routes, the cookie DISAPPEARS and is no longer sent along to the server, thus preventing me from making a request to the /refresh endpoint for a new accessToken.
// log-in controller
const User = require('../model/User');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const handleLogin = async (req, res) => {
const { user, pwd } = req.body;
if (!user || !pwd) return res.status(400).json({ 'message': 'Username and password are required.' });
const foundUser = await User.findOne({ username: user }).exec();
if (!foundUser) return res.sendStatus(401); //Unauthorized
// evaluate password
const match = await bcrypt.compare(pwd, foundUser.password);
if (match) {
const roles = Object.values(foundUser.roles).filter(Boolean);
// create JWTs
const accessToken = jwt.sign(
{
"UserInfo": {
"username": foundUser.username,
"roles": roles
}
},
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: '10s' }
);
const refreshToken = jwt.sign(
{ "username": foundUser.username },
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: '1d' }
);
// Saving refreshToken with current user
foundUser.refreshToken = refreshToken;
const result = await foundUser.save();
console.log(result);
console.log(roles);
// Creates Secure Cookie with refresh token
res.cookie('jwt', refreshToken, { httpOnly: true, secure: true, sameSite: 'None', maxAge: 24 * 60 * 60 * 1000 });
// Send authorization roles and access token to user
res.json({ roles, accessToken });
} else {
res.sendStatus(401);
}
}
module.exports = { handleLogin };
// refresh endpoint controller
const User = require('../model/User');
const jwt = require('jsonwebtoken');
const handleRefreshToken = async (req, res) => {
const cookies = req.cookies;
if (!cookies?.jwt) return res.sendStatus(401);
const refreshToken = cookies.jwt;
const foundUser = await User.findOne({ refreshToken }).exec();
if (!foundUser) return res.sendStatus(403); //Forbidden
// evaluate jwt
jwt.verify(
refreshToken,
process.env.REFRESH_TOKEN_SECRET,
(err, decoded) => {
if (err || foundUser.username !== decoded.username) return res.sendStatus(403);
const roles = Object.values(foundUser.roles);
const accessToken = jwt.sign(
{
"UserInfo": {
"username": decoded.username,
"roles": roles
}
},
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: '10s' }
);
res.json({ roles, accessToken })
}
);
}
module.exports = { handleRefreshToken }
Solution 1:[1]
The JWT refresh token is a one-off thing. So, in your code after user signs in in the JWT server, you are getting accessToken which expires in 10 seconds, and refresh token which you are saving into the user's browser cookies. After accessToken expires, you are generating new accessToken using user's refreshToken. At this moment your current refreshToken becomes outdated, and when you will try to generate one more accessToken (in 10 seconds), it will fail. So, in the handleRefreshToken() function you need to generate brand new refreshToken:
const refreshToken = jwt.sign(
{ "username": foundUser.username },
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: '1d' }
);
// Saving refreshToken with current user
foundUser.refreshToken = refreshToken;
const result = await foundUser.save();
console.log(result);
console.log(roles);
// Creates Secure Cookie with refresh token
res.cookie('jwt', refreshToken, { httpOnly: true, secure: true, sameSite: 'None', maxAge: 24 * 60 * 60 * 1000 });
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | korvin0 |
