Reputation: 3
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.
Upvotes: 0
Views: 131
Reputation: 77
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.Upvotes: 0
Reputation: 582
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:
const delay = 30 * 1000; // time in ms
// Now setting the interval your submit will run every 30 seconds
setInterval(handleSubmit, delay);
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).
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.
const delay = 30 * 1000; // time in ms
const submitWrapper = async () => {
const res = await handleSubmit();
setTimeout(submitHandler, delay);
}
setTimeout(submitHandler, delay);
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.
Upvotes: 1