f in x
Autenticazione JWT con Node.js — Access Token e Refresh Token per una Gestione Sicura delle Sessioni
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Sviluppo di siti web

Autenticazione JWT con Node.js — Access Token e Refresh Token per una Gestione Sicura delle Sessioni

[2026-06-30] Author: Ing. Calogero Bono
Zenithby Meteora Web Il sistema operativo della tua attività. Social, clienti, prenotazioni e fatture in un'unica piattaforma. Palestre, barber, professionisti. Scopri Zenith Demo gratis · senza carta

Hai un'app basata su Node.js e devi gestire l'autenticazione senza affidarti a sessioni lato server? Forse hai già sentito parlare di JWT, ma non è chiaro come gestire la scadenza dei token o come proteggere le rotte senza esporre le credenziali. Il problema è concreto: se il token viene intercettato o se non gestisci bene il refresh, l'utente perde la sessione o, peggio, lasci la porta aperta a un attacco. Noi, di Meteora Web, lavoriamo ogni giorno su backend Node.js per clienti che non possono permettersi intoppi di sicurezza. In questa guida ti mostriamo come implementare autenticazione JWT con access e refresh token in Node.js, con codice reale e accorgimenti che abbiamo imparato sul campo.

Che cos'è JWT e perché usarlo per l'autenticazione in Node.js?

JWT (JSON Web Token) è un formato compatto e autosufficiente per trasmettere informazioni in modo sicuro tra parti. A differenza delle sessioni tradizionali (che richiedono un database per mantenere lo stato), JWT contiene tutti i dati necessari dentro il token stesso, firmato digitalmente. Questo lo rende ideale per API REST e architetture stateless.

Perché Node.js e JWT si sposano bene? Node.js è asincrono e gestisce migliaia di connessioni. Con JWT eviti di dover consultare un database a ogni richiesta per verificare la sessione: basta decodificare e verificare la firma. Risparmi latenza e risorse. Ma attenzione: la comodità del "tutto nel token" nasconde delle insidie se non gestisci correttamente la scadenza e la rotazione dei token.

Access token vs refresh token: la coppia vincente

Un singolo token JWT con lunga scadenza (es. 24 ore) è rischioso: se viene rubato, l'attaccante ha accesso per troppo tempo. La soluzione standard è usare due token:

Sponsored Protocol

  • Access token — breve durata (es. 15 minuti), contiene l'identità dell'utente e i permessi. Viene inviato in ogni richiesta.
  • Refresh token — lunga durata (es. 7 giorni), utilizzato solo per ottenere un nuovo access token. Deve essere conservato in modo sicuro (es. HttpOnly cookie) e può essere revocato.

Questa architettura limita l'esposizione: anche se l'access token viene rubato, è valido poco tempo. Il refresh token non viaggia nelle richieste API normali, quindi è molto più difficile da intercettare.

Come implementare access e refresh token in un progetto Node.js?

Partiamo da un esempio pratico con Express e il pacchetto jsonwebtoken. Per il refresh token useremo un database (es. PostgreSQL o Redis) per memorizzare il token e poterlo invalidare all'occorrenza. Noi consigliamo di non memorizzare mai il refresh token in localStorage: usa un cookie HttpOnly e Secure.

1. Setup del progetto

npm init -y
npm install express jsonwebtoken bcryptjs dotenv
npm install --save-dev @types/jsonwebtoken  # se usi TypeScript

Creiamo un file .env per le chiavi segrete:

ACCESS_TOKEN_SECRET=il_tuo_segreto_molto_lungo_e_casuale
REFRESH_TOKEN_SECRET=un_altro_segreto_diverso
ACCESS_TOKEN_EXPIRES=15m
REFRESH_TOKEN_EXPIRES=7d

Mai hardcodare le chiavi. Usa variabili d'ambiente e genera chiavi sicure con openssl rand -base64 32.

Sponsored Protocol

2. Creazione dei token

const jwt = require('jsonwebtoken');

function generateAccessToken(user) {
  return jwt.sign(
    { id: user.id, ruolo: user.ruolo },
    process.env.ACCESS_TOKEN_SECRET,
    { expiresIn: process.env.ACCESS_TOKEN_EXPIRES }
  );
}

function generateRefreshToken(user) {
  return jwt.sign(
    { id: user.id },
    process.env.REFRESH_TOKEN_SECRET,
    { expiresIn: process.env.REFRESH_TOKEN_EXPIRES }
  );
}

Il refresh token contiene solo l'ID utente, non i permessi. Se devi revocarlo, lo salvi nel database in modo da poterlo invalidare.

3. Flusso di login

app.post('/login', async (req, res) => {
  // Valida credenziali...
  const user = { id: 123, ruolo: 'admin' };

  const accessToken = generateAccessToken(user);
  const refreshToken = generateRefreshToken(user);

  // Salva il refresh token (es. in database)
  await saveRefreshToken(user.id, refreshToken);

  // Invia access token in body, refresh token in cookie sicuro
  res.cookie('refreshToken', refreshToken, {
    httpOnly: true,
    secure: true,       // solo HTTPS
    sameSite: 'strict',
    maxAge: 7 * 24 * 60 * 60 * 1000
  });
  res.json({
    accessToken,
    expiresIn: 900 // 15 minuti in secondi
  });
});

L'access token va inviato nell'header Authorization: Bearer <token> dal client. Il refresh token non deve mai essere accessibile via JavaScript (HttpOnly).

4. Middleware per proteggere le rotte

function authenticateToken(req, res, next) {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];
  if (!token) return res.sendStatus(401);

  jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
    if (err) {
      if (err.name === 'TokenExpiredError') {
        return res.status(401).json({ error: 'Token scaduto', code: 'TOKEN_EXPIRED' });
      }
      return res.sendStatus(403);
    }
    req.user = user;
    next();
  });
}

5. Rotta per il refresh

app.post('/refresh', async (req, res) => {
  const refreshToken = req.cookies.refreshToken;
  if (!refreshToken) return res.sendStatus(401);

  // Verifica che il token sia ancora valido nel database
  const stored = await getRefreshToken(refreshToken);
  if (!stored) return res.sendStatus(403);

  jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);

    // Genera nuovo access token e nuovo refresh token (rotazione)
    const newAccessToken = generateAccessToken({ id: user.id, ruolo: stored.ruolo });
    const newRefreshToken = generateRefreshToken({ id: user.id });

    // Invalida il vecchio refresh token e salva il nuovo
    await revokeRefreshToken(refreshToken);
    await saveRefreshToken(user.id, newRefreshToken);

    res.cookie('refreshToken', newRefreshToken, {
      httpOnly: true,
      secure: true,
      sameSite: 'strict',
      maxAge: 7 * 24 * 60 * 60 * 1000
    });
    res.json({ accessToken: newAccessToken, expiresIn: 900 });
  });
});

La rotazione del refresh token è fondamentale: ogni volta che usi un refresh token, lo sostituisci con uno nuovo. Se un attaccante ruba un refresh token e lo usa, il token legittimo viene invalidato. Se il legittimo proprietario tenta di usare quello vecchio, capisci che c'è stato un furto e puoi revocare tutti i token associati.

Sponsored Protocol

Quali sono le migliori pratiche di sicurezza per JWT in Node.js?

La sicurezza non si ferma alla firma del token. Ecco gli accorgimenti che noi di Meteora Web applichiamo in ogni progetto.

Sponsored Protocol

Non mettere dati sensibili nel payload

JWT è firmato ma non crittografato. Chiunque può decodificarlo (base64). Non inserire password, numeri di carta di credito o dati personali non necessari. Usa solo identificatori e permessi.

Usa chiavi diverse per access e refresh

Se un segreto viene compromesso, l'altro rimane sicuro. Inoltre, per ambienti più esigenti, considera chiavi asimmetriche (RS256) per la firma dei token.

Cookie HttpOnly per il refresh token

Non salvare mai il refresh token in localStorage o sessionStorage: sono vulnerabili a XSS. I cookie con flag HttpOnly, Secure e SameSite sono la scelta più sicura.

Implementa blacklist o revoca

Quando un utente fa logout, invalida il refresh token (cancella dal database). In più, per scenari di furto, tieni una lista nera di token scaduti ma ancora validi (es. in Redis con TTL). Noi lo gestiamo con una tabella refresh_tokens con campo revoked_at.

Limita la validità temporale

Access token: 15 minuti massimo. Refresh token: 7 giorni per la maggior parte delle app. Per app bancarie o healthcare, riduci ulteriormente. Ricorda: più lungo è il refresh token, maggiore è il rischio in caso di furto.

Sponsored Protocol

Proteggi le rotte di refresh da attacchi CSRF

Poiché il refresh token è in un cookie, potrebbe essere inviato automaticamente in una richiesta cross-site. Usa il flag sameSite: 'strict' e, per maggiore sicurezza, un header anti-CSRF (es. X-Requested-By o token CSRF nel corpo).

Log e monitoraggio

Tieni traccia di tutti i tentativi di refresh falliti, specialmente quando un token già revocato viene riutilizzato. Potrebbe indicare un attacco in corso.

Cosa fare adesso

Hai visto come implementare l'autenticazione JWT con access e refresh token in Node.js, con attenzione alla sicurezza. Ora tocca a te:

  1. Scarica il pacchetto jsonwebtoken e inizia a costruire il tuo sistema di login.
  2. Integra il refresh token in un database (Redis è ideale per le performance).
  3. Proteggi il refresh token con cookie HttpOnly e Secure e implementa la rotazione.
  4. Testa lo scenario di furto — simula un attacco XSS e verifica che il refresh token non sia accessibile.
  5. Controlla i log per rilevare usi anomali dei refresh token.

Se il tuo stack è Node.js e vuoi un backend sicuro senza reinventare la ruota, noi di Meteora Web possiamo aiutarti a progettarlo. Abbiamo costruito piattaforme con autenticazione JWT per clienti di tutta Italia, partendo sempre dai numeri e dalla sicurezza. Per approfondire l'uso di Node.js nel tuo progetto, dai un'occhiata alla nostra guida madre su Node.js per il backend.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere informatico, fondatore di Meteora Web e Zenith OS. System administrator e progettista di piattaforme, app e CMS proprietari, con esperienza in sviluppo full-stack, marketing digitale ed ecosistema Google.
[ Read Full Dossier ]

> METEORA_WEB // WEB AGENCY

Costruiamo la presenza digitale che la tua azienda merita.

Siti web, social, pubblicità online, e-commerce e hosting performante: ingegnerizzati con metodo da ingegneri informatici a Sciacca, per tutta Italia.

> MW_JOURNAL

> READ_ALL()