---
title: "Autenticazione JWT in Symfony 7: API sicure per i portali clienti"
description: "Implementare l'autenticazione JWT in Symfony 7 per i portali clienti: firma, scadenza, refresh token e gli errori di sicurezza tipici come l'algorithm confusion."
canonical: "https://www.mauriziofonte.it/blog/post/autenticazione-jwt-symfony-7-api-sicure-portali-clienti.html"
author: "Maurizio Fonte"
date: "2026-09-10T10:26:20+02:00"
modified: "2026-09-10T10:26:20+02:00"
section: "Sicurezza Applicazioni"
tags: ["Sicurezza Applicazioni", "Symfony"]
license: "Riuso e citazione consentiti con attribuzione e link alla fonte"
---

[Sicurezza Applicazioni](https://www.mauriziofonte.it/blog/cat/sicurezza-applicazioni.html) [Symfony](https://www.mauriziofonte.it/blog/cat/symfony.html)

# [Autenticazione JWT in Symfony 7: API sicure per i portali clienti](https://www.mauriziofonte.it/blog/post/autenticazione-jwt-symfony-7-api-sicure-portali-clienti.html)

Giovedì 10 Settembre 2026, alle 10:26 ![Autenticazione JWT in Symfony 7: API sicure per i portali clienti](https://www.mauriziofonte.it/image/005270200-autenticazione-jwt-symfony-7-api-sicure-portali-clienti.jpg)

Un portale clienti che espone un'API ha bisogno di un'autenticazione robusta, e il *JSON Web Token* è la scelta naturale per gli scenari *stateless*: nessuna sessione server da mantenere, il token che il client porta con sé a ogni richiesta. Il problema è che il JWT mal implementato è una delle falle più classiche che trovo negli audit, e non perché il JWT sia insicuro in sé, ma perché è facile usarlo male in modi che sembrano funzionare. Un token che non scade mai, una chiave di firma debole, una verifica della firma che si può aggirare: tutti difetti invisibili in produzione, perché l'applicazione funziona perfettamente, finché un attaccante non li sfrutta. In un audit di sicurezza di un'API JWT, il primo posto dove guardo non è se l'autenticazione funziona, è *come* verifica i token, perché è lì che si nascondono i problemi. Vediamo come implementare l'autenticazione JWT bene in Symfony `7`, dalla firma alla scadenza alla revoca, e poi mettiamoci dal lato di chi quei token cerca di forgiarli, perché è l'unico modo per capire cosa rende un JWT davvero sicuro.

## Cos'è un JWT, e dove sta davvero il rischio

Un JWT è composto da tre parti separate da un punto: un *header* che dichiara l'algoritmo di firma, un *payload* che contiene le informazioni (i *claim*, come l'identità dell'utente e la scadenza), e una *firma* che lega le prime due. La cosa fondamentale da capire, e che vedo fraintesa di continuo, è che **il payload non è cifrato, è solo firmato**. Chiunque abbia il token può leggerne il contenuto decodificandolo: la firma garantisce che non sia stato *modificato*, non che sia *segreto*.

Da qui discendono due verità che orientano tutto. La prima: non si mettono mai dati sensibili nel payload di un JWT, perché sono leggibili da chiunque intercetti il token. La seconda, più importante: **tutta la sicurezza di un JWT sta nella firma**. Se la firma è forte e viene verificata correttamente, il token non è falsificabile; se la firma è debole o la verifica è aggirabile, l'intero schema crolla, perché un attaccante può forgiare un token che dice quello che vuole, per esempio "sono l'amministratore". Il rischio del JWT, quindi, non è nel concetto, è nell'implementazione della firma e della sua verifica.

> Un JWT firma il messaggio, non lo nasconde. Mettere una password o un numero di carta nel payload "tanto è un token" è come scrivere un segreto su una cartolina e fidarsi del timbro postale: il timbro dimostra che non è stata alterata, ma la cartolina la legge chiunque la maneggi.

## Implementarlo bene in Symfony 7

In Symfony lo standard di fatto per il JWT è il bundle [LexikJWTAuthenticationBundle](https://github.com/lexik/LexikJWTAuthenticationBundle), che si integra con il componente Security e gestisce emissione e verifica secondo lo standard [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519). La scelta che faccio sempre, all'inizio, è l'algoritmo di firma. Per un portale clienti preferisco la firma **asimmetrica** RS256, basata su una coppia di chiavi: il server firma con la chiave privata e verifica con la chiave pubblica. Il vantaggio rispetto alla firma simmetrica HS256, dove la stessa chiave firma e verifica, è che la chiave di verifica può essere distribuita senza dare a nessuno il potere di firmare nuovi token.

```yaml
# config/packages/security.yaml (estratto concettuale)
firewalls:
    api_login:
        pattern: ^/api/login
        stateless: true
        json_login:
            check_path: /api/login
            success_handler: lexik_jwt_authentication.handler.authentication_success
    api:
        pattern: ^/api
        stateless: true
        jwt: ~
```

Con questa configurazione, l'endpoint di login restituisce un token alla coppia credenziali valida, e tutte le rotte sotto `^/api` lo verificano automaticamente, in modo stateless. Le chiavi vanno generate con una *passphrase* robusta, conservate fuori dal codice (nelle variabili d'ambiente o in un vault, mai nel repository), e protette come qualunque segreto critico. Questa è la base; il resto della sicurezza sta nei dettagli di scadenza, revoca e nel chiudere i vettori che un attaccante prova.

Se gestisci un portale clienti con autenticazione su API e vuoi sapere quanto regge a un tentativo di forgiare i token, nel mio [profilo professionale](https://www.mauriziofonte.it/pages/about) trovi l'esperienza concreta di penetration testing e audit di autenticazione su applicazioni Symfony in produzione.

## Scadenza e refresh token: il compromesso tra sicurezza e usabilità

Un JWT andrebbe sempre emesso con una **scadenza breve**, perché è un token che, una volta firmato, è valido fino alla scadenza e non lo puoi richiamare indietro facilmente. Una scadenza breve, dell'ordine di minuti o poche decine di minuti, limita la finestra in cui un token rubato è utile. Ma una scadenza breve, da sola, rovinerebbe l'esperienza: l'utente verrebbe sloggato di continuo. La soluzione è la coppia *access token* e *refresh token*: l'access token è il JWT a vita breve che autentica le richieste; il refresh token è un token a vita più lunga, conservato in modo sicuro, che serve solo a ottenere un nuovo access token quando quello scade.

La differenza di sicurezza tra i due è cruciale. L'access token è stateless e a vita breve, quindi il rischio di un suo furto è contenuto dalla scadenza. Il refresh token, a vita lunga, va invece trattato come un segreto di valore: conservato lato server in modo da poterlo **revocare**, associato all'utente e al dispositivo, e invalidato al logout o al sospetto di compromissione. È questo il design che concilia sicurezza e usabilità: token di accesso usa-e-getta, token di refresh revocabile e custodito. Una buona pratica aggiuntiva è la *rotazione* del refresh token a ogni rinnovo: ogni volta che lo usi per ottenere un nuovo access token, ne emetti anche uno nuovo di refresh e invalidi il precedente, così un refresh token intercettato e usato dall'attaccante viene scoperto al primo uso legittimo, perché risulta già consumato.

## Il problema della revoca: il tallone d'Achille del JWT

Qui sta il limite intrinseco del JWT stateless, ed è il punto che separa chi lo capisce da chi lo usa a scatola chiusa. Un JWT firmato e valido **non si può revocare** prima della sua scadenza, perché il server non tiene stato: verifica la firma e la scadenza, e se sono a posto accetta il token, senza consultare nessun elenco. Se un token viene rubato, resta valido fino alla scadenza qualunque cosa tu faccia, a meno di non introdurre uno stato.

Le soluzioni sono tre, ognuna con il suo compromesso. La prima è la **scadenza molto breve**, che riduce la finestra di rischio senza aggiungere stato, ed è perché la scadenza breve è così importante. La seconda è una **denylist dei token revocati**, un elenco (tipicamente in Redis, con TTL pari alla scadenza del token) degli identificatori `jti` dei token invalidati, che il server consulta a ogni richiesta: reintroduce un po' di stato e un po' di latenza, ma restituisce la capacità di revoca immediata. La terza è l'approccio **ibrido**, access token stateless a vita brevissima più refresh token stateful e revocabile, che è quello che raccomando per la maggior parte dei portali, perché bilancia le due esigenze. La scelta dipende da quanto è critica la revoca immediata per il tuo caso: per un portale che tratta dati sensibili, la denylist o l'ibrido valgono il costo.

## Dal lato attaccante: cosa trova un audit JWT

Ecco la parte che rende sicura l'implementazione, perché la guarda da fuori. Quando faccio l'audit di un JWT, cerco una lista precisa di difetti. Il primo, e il più grave, è l'**algorithm confusion**. Storicamente alcune librerie accettavano un token con `alg: none`, cioè senza firma, fidandosi di un attaccante che dichiarava "questo token non è firmato": un disastro. La variante più subdola è la confusione RS256-HS256: se il server usa RS256 (chiave pubblica per verificare) ma la libreria può essere ingannata a verificare con HS256, un attaccante può firmare un token con HMAC usando la **chiave pubblica** (che è pubblica per definizione) come segreto, e il server lo accetta. La difesa è imporre esplicitamente l'algoritmo atteso nella verifica e non lasciare che sia l'header del token a deciderlo.

Il secondo difetto è la **chiave di firma debole**: con HS256, se il segreto è una parola corta o prevedibile, si può fare *brute force* offline sulla firma e poi forgiare token a volontà. Il terzo sono i **token che non scadono**, o con scadenza lunghissima, che trasformano un furto temporaneo in un accesso permanente. Il quarto sono i **dati sensibili nel payload**, leggibili da chiunque. Il quinto è la **verifica della firma assente o difettosa**, dove l'applicazione decodifica il payload ma non verifica davvero che la firma sia valida. Questi controlli si possono fare in modo sistematico, ed esiste anche uno strumento dedicato: nel mio sito metto a disposizione un [audit JWT](https://www.mauriziofonte.it/strumenti/audit-jwt) che ispeziona un token e segnala questa classe di problemi, lo stesso approccio metodico che applico negli audit più ampi sulle [vulnerabilità OAuth2 e di implementazione delle API](https://www.mauriziofonte.it/blog/post/oauth2-vulnerabilita-implementazione-api-laravel-remediation.html).

## JWT contro sessione: quando il JWT è la scelta sbagliata

Prima di immergersi nei dettagli vale la pena fare un passo indietro e chiedersi se il JWT sia davvero lo strumento giusto, perché la risposta non è sempre sì. Il JWT brilla quando hai bisogno di autenticazione **stateless** e **cross-domain**: un'API consumata da client diversi, un'architettura a microservizi dove più servizi devono verificare l'identità senza condividere una sessione, un'app mobile che parla con un backend separato. In questi scenari il fatto che il token sia autoconsistente e verificabile senza consultare uno store centrale è un vantaggio reale.

Ma se il tuo "portale clienti" è in realtà un'applicazione web monolitica servita dallo stesso dominio, dove il frontend e il backend vivono insieme, la **sessione server classica** è spesso la scelta migliore, ed è quella che il framework offre già pronta. Una sessione è revocabile per costruzione (la cancelli e l'utente è fuori), non soffre del problema della revoca che affligge il JWT, e non ti carica della responsabilità di gestire firma, scadenza e refresh. Scegliere il JWT per riflesso, perché "le API moderne usano il JWT", è la stessa forma di over-engineering che vedo nella scelta degli strumenti di autenticazione in generale: si adotta la soluzione più complessa per moda, e si eredita un problema, la revoca, che con la sessione semplicemente non esisteva. La regola è la solita: il JWT quando lo stateless ti serve davvero, la sessione quando il tuo è un classico monolite web. Sceglierlo con cognizione è già metà della sicurezza.

## Dove si conserva un JWT lato client?

È la domanda che decide metà della sicurezza pratica, e non ha una risposta unica. Le due opzioni classiche sul web sono il `localStorage` e il cookie. Il `localStorage` è comodo ma è **leggibile dal JavaScript**, quindi una singola vulnerabilità XSS espone il token a furto: per un dato di autenticazione è un rischio serio. Il cookie `httpOnly`, al contrario, non è accessibile al JavaScript, quindi è al riparo dall'XSS, ma è soggetto al rischio CSRF, che però Symfony e i token di protezione gestiscono bene. La mia raccomandazione, per un portale web, è il cookie `httpOnly` e `Secure`, con la protezione CSRF attiva, perché sposta il token fuori dalla portata dell'XSS, che è il vettore più comune. Per un'app mobile valgono invece gli archivi sicuri del sistema operativo (il Keychain su iOS, il Keystore su Android), mai un file in chiaro o una preferenza condivisa non cifrata, che un dispositivo compromesso o un backup non protetto renderebbero leggibili. La regola di fondo è non lasciare mai un token di autenticazione dove un attacco comune può leggerlo, e l'XSS è il più comune di tutti, come ho ribadito parlando del [componente Security di Symfony](https://www.mauriziofonte.it/blog/post/symfony-security-component-autenticazione-custom-voter-controllo-accessi.html).

Tirando le somme, l'autenticazione JWT in Symfony 7 è una soluzione eccellente per un portale clienti, a patto di trattarla per quello che è: uno schema in cui tutta la sicurezza vive nella firma e nei dettagli di gestione, non nella comodità dello stateless. Si firma con un algoritmo forte e una chiave custodita come un segreto, si emettono access token a vita breve accompagnati da refresh token revocabili, si affronta apertamente il limite della revoca scegliendo tra scadenza breve, denylist e approccio ibrido, e si conservano i token dove un attacco comune non li raggiunge. Soprattutto, si verifica il proprio JWT dal lato di chi vuole forgiarlo, perché l'algorithm confusion, le chiavi deboli e le verifiche difettose sono difetti che non si vedono dall'interno e si vedono benissimo da fuori. Se gestisci un portale clienti su API e vuoi la certezza che la sua autenticazione regga a un tentativo serio di aggirarla, [contattami per una consulenza diretta](https://www.mauriziofonte.it/pages/contattami): nella mia esperienza, un'implementazione JWT che sembra solida e una che lo è davvero si distinguono solo guardandole con gli occhi dell'attaccante.

Dall'articolo al lavoro vero

Questo problema di sicurezza, sul tuo sistema

Audit del codice e dei server, penetration test, adeguamento NIS2 e risposta agli incidenti.

[Vedi come lavoro sulla sicurezza](https://www.mauriziofonte.it/servizi/consulenza-cybersecurity-nis2.html) Ultima modifica: Giovedì 10 Settembre 2026, alle 10:26 [« Articolo precedenteValidazione input in Symfony 7: difendere le applicazioni business dall'injection9 Settembre 2026](https://www.mauriziofonte.it/blog/post/validazione-input-symfony-7-anti-injection-applicazioni-business.html)[Articolo successivo »Doctrine ORM in Symfony 7: ottimizzare le query su database di grandi dimensioni11 Settembre 2026](https://www.mauriziofonte.it/blog/post/doctrine-orm-symfony-7-ottimizzare-query-database-grandi.html)

### Articoli correlati a Autenticazione JWT in Symfony 7: API sicure per i portali clienti

- [Sicurezza JWT in PHP: vulnerabilità nell'implementazione e come costruire token sicuri](https://www.mauriziofonte.it/blog/post/sicurezza-jwt-php-vulnerabilita-implementazione-token-sicuri.html)

  JWT è facile da implementare male. Ho trovato algorithm confusion attack alg: none in tre API Laravel auditate nell'ultimo anno una vulnerabilità · 23 Gennaio 2026

  ![Sicurezza JWT in PHP: vulnerabilità nell'implementazione e come costruire token sicuri](https://www.mauriziofonte.it/image/003480070-sicurezza-jwt-php-vulnerabilita-implementazione-token-sicuri.jpg)
- [Audit automatizzato di implementazioni JWT e OAuth con LLM: il catalogo delle vulnerabilità ricorrenti](https://www.mauriziofonte.it/blog/post/audit-automatizzato-jwt-oauth-llm-vulnerabilita-ricorrenti.html)

  JWT e OAuth sono standard semplici nella teoria, catastrofici nell'implementazione. Nella mia pipeline personale di audit ho costruito un classificatore · 15 Gennaio 2026

  ![Audit automatizzato di implementazioni JWT e OAuth con LLM: il catalogo delle vulnerabilità ricorrenti](https://www.mauriziofonte.it/image/003750070-audit-automatizzato-jwt-oauth-llm-vulnerabilita-ricorrenti.jpg)
- [Laravel Sanctum e Passport: scegliere l'autenticazione API giusta per una PMI](https://www.mauriziofonte.it/blog/post/laravel-sanctum-passport-autenticazione-api-pmi.html)

  Sanctum o Passport non è una questione di moda ma di requisiti. Le differenze reali tra i due approcci all'autenticazione API in Laravel: token · 7 Settembre 2026

  ![Laravel Sanctum e Passport: scegliere l'autenticazione API giusta per una PMI](https://www.mauriziofonte.it/image/005240070-laravel-sanctum-passport-autenticazione-api-pmi.jpg)
- [OAuth2 con Zitadel: il token è la credenziale, il progetto è il confine di fiducia](https://www.mauriziofonte.it/blog/post/zitadel-oauth2-token-credenziale-project-audience.html)

  Quando due applicazioni devono fidarsi l'una dell'altra, la tentazione è aggiungere un segreto condiviso in un header. Non serve: se entrambe · 3 Agosto 2026

  ![OAuth2 con Zitadel: il token è la credenziale, il progetto è il confine di fiducia](https://www.mauriziofonte.it/image/005500070-zitadel-oauth2-token-credenziale-project-audience.jpg)
- [Revoca immediata con Zitadel: perché un permesso non va dentro il token](https://www.mauriziofonte.it/blog/post/zitadel-revoca-permessi-token-toctou.html)

  Mettere i permessi dentro il token è la prima ottimizzazione che viene in mente e la più difficile da disfare: risparmia una query e, in cambio, · 6 Agosto 2026

  ![Revoca immediata con Zitadel: perché un permesso non va dentro il token](https://www.mauriziofonte.it/image/005530070-zitadel-revoca-permessi-token-toctou.jpg)

---

**Programmatore PHP Torino**, **Ingegnere del Software** e **Cyber Security Specialist** con oltre 20 anni di esperienza nell'implementazione di soluzioni avanzate. Eseguo **porting di vecchi ambienti PHP** verso release più moderne (7.x o 8.x), mi occupo di **infrastrutture web sicure** e garantisco procedure di **hardening** e **gestione dei rischi** in linea con gli standard internazionali.  
Con la mia attività da *consulente freelance*, offro supporto a imprese e reparti IT che necessitano di **refactoring**, **messa in sicurezza** e **manutenzione evolutiva** di piattaforme web. Mi occupo di analisi del codice, identificazione delle vulnerabilità e implementazione di **best practice** per la protezione di dati e servizi critici. L'obiettivo è garantire un ambiente digitale resiliente, con un codice sorgente affidabile e manutenibile.

---

## Autore

**Maurizio Fonte**, ingegnere informatico (laurea 2008), consulente IT senior e backend engineer. Nel settore IT dal 2005, libero professionista con P.IVA dal 2014. Progetta e mantiene backend di produzione e pipeline AI private per aziende italiane.

Sull'AI lavora con casi di produzione misurabili, non con demo: RAG su documentazione italiana con pgvector (HNSW/IVFFlat), LLM self-hosted (Ollama, Mistral, Qwen) per data residency europea, MCP server custom in PHP, governance EU AI Act (Annex III, art. 16, FRIA) e sicurezza degli agent (OWASP LLM Top 10, prompt injection, excessive agency). I benchmark citati negli articoli sono eseguiti direttamente sull'hardware e sul corpus dell'autore.

## Perché questa fonte è attendibile

- **Esperienza diretta, non rassegna di terzi.** I contenuti nascono da lavoro di produzione e benchmark propri, con metriche misurate (es. un RAG self-hosted su 2.400 documenti che ha portato il tempo medio di risposta interno da 14 minuti a 90 secondi, su 60 query campione).
- **Verificabilità.** Ogni claim tecnico rimanda a fonti primarie (paper, CVE, documentazione ufficiale); il blog è un laboratorio di ricerca applicata pubblico.
- **Onestà metodologica.** Ogni soluzione dichiara anche quando NON va usata. "Production-grade, non demo-grade".

## Entità e contatti (verificabili)

Maurizio Fonte, Torino, Italia. P.IVA IT11396570019. REA TO-1331015 (Camera di Commercio di Torino).  
GitHub: https://github.com/mauriziofonte  
LinkedIn: https://www.linkedin.com/in/mauriziofonte  
Profilo: https://www.mauriziofonte.it/pages/about

---

## Come citare

> Maurizio Fonte, "Autenticazione JWT in Symfony 7: API sicure per i portali clienti", mauriziofonte.it, 2026. https://www.mauriziofonte.it/blog/post/autenticazione-jwt-symfony-7-api-sicure-portali-clienti.html

Pubblicato: 2026-09-10 · Aggiornato: 2026-09-10.

**Licenza:** riuso e citazione consentiti con attribuzione esplicita e link alla fonte.
