I have a problem with refresh token, login api send accessToken (expiration: 30s), refreshToken (expiration: 5min) and cookie ‘refreshCookie’ (expiration: 5min). This api works correcty.
login.js (backend)
const express = require('express');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const { promisify } = require('util');
const conn = require('../db_connection');
require('dotenv').config();
const router = express.Router(); // Inizializzazione di un oggetto router
const query = promisify(conn.query).bind(conn); // Permette di far eseguire le query del database in modo asincrono
// Route per il login
router.post('/login', async (req, res) => {
try {
const { email, password } = req.body; // Ottieni i dati dal body della richiesta
// Verifica se l'email è registrata
const users = await query('SELECT * FROM users WHERE email = ?', [email]);
// Email non registrata
if (users.length === 0) {
return res.status(401).json({ error: 'Utente non registrato' });
}
const user = users[0];
const userId = user.user_id;
// Verifica se la password è corretta
const passwordMatch = await bcrypt.compare(password, user.password);
// Password sbagliata
if (!passwordMatch) {
return res.status(401).json({ error: 'La password è sbagliata' });
}
// Creazione di un token jwt di accesso
const accessToken = jwt.sign({ user_id: userId }, process.env.ACCESS_TOKEN_SECRET, { expiresIn: '30s' });
// Creazione di un refresh token
const refreshToken = jwt.sign({ user_id: userId }, process.env.REFRESH_TOKEN_SECRET, { expiresIn: '5m' })
// Creazione di un cookie per l'autenticazione dell'utente
res.cookie('refreshCookie', refreshToken, {
httpOnly: true, // Accessibile solo da server web
secure: false, // true = solo https, false = https e http
sameSite: 'None', // Cross-site cookie (il frontend è su un server diverso)
maxAge: 5 * 60 * 1000 // 5 min in ms
});
res.json({ accessToken, refreshToken });
} catch (error) {
console.log("errore login: ", error);
return res.status(500).json({ error: "Errore durante il login" });
}
});
module.exports = router;
This api is for token refresh, when accessToken has expired, client should send a request at end point /refresh-token to get a new access token if refreshToken has not expired.
refresh_token.js (backend)
const express = require('express');
const jwt = require('jsonwebtoken');
const { promisify } = require('util');
const conn = require('../db_connection');
require('dotenv').config();
const router = express.Router(); // Inizializzazione di un oggetto router
const query = promisify(conn.query).bind(conn); // Permette di far eseguire le query del database in modo asincrono
// Route per refreshare il token jwt
router.post('/refresh-token', async (req, res) => {
const cookies = req.cookies;
if (!cookies?.refreshCookie) {
return res.status(401).json({ error: "Utente non autorizzato" });
}
const refreshToken = cookies.refreshCookie;
try {
const decoded = jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET);
const user = await query("SELECT * FROM users WHERE user_id = ?", [decoded.user_id]); // Cerca l'utente nel database
// Utente non trovato
if (!user) {
res.status(401).send({ error: "Unauthorized" });
}
// Creazione di un token jwt di accesso
const accessToken = jwt.sign({ user_id: decoded.user_id }, process.env.ACCESS_TOKEN_SECRET, { expiresIn: '30s' });
res.json({ accessToken });
} catch (error) {
console.log("nErrore refresh: ", error);
return res.status(403).send({ error: "Forbidden" });
}
});
module.exports = router;
this is my frontend request, someone could help me to make the client doing a request at end point /refresh-token when accessToken has expired to get a new access token? I want to use axios and cookies to save tokens. I want that the token being refresh only when the old token has expired.
login.js (frontend)
// Funzione che invia una richiesta al server e restituisce la risposta
async function handleSubmit(e) {
e.preventDefault();
try {
const response = await axios.post(`${config.API_BASE_URL}/api/login`, { formData }, {
withCredentials: true
});
const { accessToken } = response.data;
Cookies.set('accessToken', accessToken);
navigate("/");
} catch (error) {
console.error("Errore login: ", error);
setError(error.response.data.error); // Gestisci altri tipi di errore di login
}
}
I have tried whit axios interceptor but it doesn’t work, I prefer to use this method.
2
Answers
First of all 30 second seems to me very short. Maybe consider to extend that time.
I guess what you want here is setting a setTimeout or a setInterval. Both are global functions available by js.
Basically you want to do soemthing like this:
Interval (prefered solution)
To this solution you can also add some sort of checking if the access token is really outdated, if it is not you can wait for it (e.g. using setTimeout).
Timeout (just here as an alternative)
Some people would probably consider this as a valid set up. But I would not reccomend it! But to be complete here would be soutlion using setTimeout.
Note I am only showing how to call the intervall or the timeout. How this fits into your initial call or into your app is something else to be discussed. Feel free to ask a little more specific questions for further support.
You don’t have to fetch in the background every second(s) just to check if access token is still valid. Let the user/client trigger the action for you.
Scenario:
to other route).
accessToken
expired.accessToken
expired.accessToken
by sendingrefreshToken
to your/refresh-token
endpoint.refreshToken
still valid.accessToken
and send it to client.