skip to Main Content

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


  1. 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)

    
    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).

    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.

    
    
    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.

    Login or Signup to reply.
  2. 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:

    1. the logged in user send a request (e.g. by refreshing the page, navigating
      to other route
      ).
    2. server say recieved accessToken expired.
    3. client recieve the message that accessToken expired.
    4. therefore client request a new accessToken by sending refreshToken to your /refresh-token endpoint.
    5. server verify that sent refreshToken still valid.
    6. server generate a new accessToken and send it to client.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search