I have a problem with the refresh token, login API sends accessToken (expiration: 30s), refreshToken (expiration: 5min), and cookie 'refreshCookie' (expiration: 5min). This API works correctly.
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 the token refresh, when accessToken has expired, the client should send a request at endpoint/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 do a request at endpoint/refresh-token when accessToken has expired to get a new access token? I want to use Axios and cookies to save tokens. I want the token to be refreshed 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 with Axios interceptor but it doesn't work, I prefer to use this method.
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:
accessToken
expired.accessToken
expired.accessToken
by sending refreshToken
to your /refresh-token
endpoint.refreshToken
still valid.accessToken
and send it to client.