I’ve encountered an issue while developing a Node.js application that uses JWT tokens for authentication. Currently, each time the access token expires, it seems necessary to ask users to manually log out and log back in to generate a new token. This isn’t ideal for user experience.
I’m using Express.js with JWT for handling authentication and have set up a /refresh-token endpoint to renew the access token using the refresh token. However, the renewal process doesn’t happen automatically when the token expires.
Here’s a simplified snippet of my code:
app.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
const user = await dao.findUserByUsername(username);
if (!user) {
return res.status(401).json({ error: 'Nom d'utilisateur ou mot de passe invalide' });
}
const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) {
return res.status(401).json({ error: 'Nom d'utilisateur ou mot de passe invalide' });
}
const sessionId = new Date().getTime().toString();
const token = jwt.sign({ userId: user.id, username: user.username }, JWT_SECRET, { expiresIn: JWT_EXPIRATION_TIME });
const refreshToken = jwt.sign({ userId: user.id, username: user.username }, REFRESH_TOKEN_SECRET, { expiresIn: REFRESH_TOKEN_EXPIRATION_TIME });
res.json({ token });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
const verifyToken = (req, res, next) => {
const token = req.headers.authorization;
const refreshToken = req.headers['x-refresh-token'];
if (!token) {
return res.status(403).json({ error: 'Un token est requis pour accéder à cette ressource' });
}
jwt.verify(token.split(' ')[1], JWT_SECRET, (err, decodedToken) => {
if (err) {
if (err.name === 'TokenExpiredError' && refreshToken) {
jwt.verify(refreshToken, REFRESH_TOKEN_SECRET, (err, decodedRefreshToken) => {
if (err) {
return res.status(401).json({ error: 'Token de renouvellement invalide' });
}
const newAccessToken = jwt.sign({ userId: decodedRefreshToken.userId }, JWT_SECRET, { expiresIn: JWT_EXPIRATION_TIME });
res.setHeader('x-new-access-token', newAccessToken);
req.user = decodedRefreshToken;
next();
});
} else {
console.error('Erreur de vérification du token :', err);
return res.status(401).json({ error: 'Token invalide ou expiré' });
}
} else {
req.user = decodedToken;
next();
}
});
};
app.post('/refresh-token', (req, res) => {
const refreshToken = req.body.refreshToken;
if (!refreshToken) {
return res.status(403).json({ error: 'Un token de renouvellement est requis' });
}
jwt.verify(refreshToken, REFRESH_TOKEN_SECRET, (err, decodedRefreshToken) => {
if (err) {
console.error('Erreur de vérification du token de renouvellement :', err);
return res.status(401).json({ error: 'Token de renouvellement invalide' });
}
const newAccessToken = jwt.sign({ userId: decodedRefreshToken.userId }, JWT_SECRET, { expiresIn: JWT_EXPIRATION_TIME });
res.json({ accessToken: newAccessToken });
});
});
app.get('/protected', verifyToken, (req, res) => {
res.json({ message: 'Ceci est une route protégée' });
});
app.put('/edit-user', verifyToken, async (req, res) => {
try {
const { username, password } = req.body;
const userId = req.user.userId;
const existingUser = await dao.findUserById(userId);
if (!existingUser) {
return res.status(404).json({ error: 'Utilisateur non trouvé' });
}
const hashedPassword = await bcrypt.hash(password, 10);
await dao.updateUser(userId, username, hashedPassword);
res.json({ success: true });
} catch (err) {
res.status(500).json({ error: 'Erreur serveur' });
}
});
user23298973 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.