Ogni giorno, gli utenti accedono a servizi digitali: controllano la posta elettronica, effettuano acquisti online, consultano il proprio conto bancario o collaborano su documenti condivisi. In tutti questi scenari, c’è un momento in cui il sistema verifica chi sei e cosa puoi fare.
Parliamo quindi di Autenticazione e Autorizzazione, due concetti distinti ma profondamente interconnessi. Nel corso degli anni si sono sviluppati diversi meccanismi per affrontare queste sfide: Sessioni, Token, JWT, SSO e OAuth, ognuno nato per rispondere a esigenze specifiche, e ognuno con i suoi vantaggi, limitazioni e scenari d’uso ottimali.
Sessioni e Token
Il meccanismo basato su sessioni è il più classico e consolidato nello sviluppo web. Nasce come soluzione diretta al problema dell’assenza di stato di HTTP, introducendo uno stato persistente lato server. Il flusso completo è il seguente
- L’utente invia username e password al server tramite un form di login
- Il server verifica le credenziali confrontandole con il database utenti
- Se le credenziali sono corrette, il server genera un identificatore di sessione (Session ID) univoco e casuale
- Il Session ID viene memorizzato nel database del server, associato ai dati dell’utente (ruoli, permessi, timestamp di creazione e scadenza)
- Il server restituisce il Session ID al client, solitamente sotto forma di cookie HTTP
- Ad ogni richiesta successiva, il browser invia automaticamente il cookie con il Session ID
- Il server riceve il Session ID, lo cerca nel database e, se trovato e valido, identifica l’utente e processa la richiesta
Le sessioni hanno tipicamente una durata limitata (es. 30 minuti di inattività, o 24 ore assolute) ed il server può invalidare una sessione in qualsiasi momento semplicemente eliminandola o marcandola come revocata nel database.
Il limite delle sessioni server-side emerge quando si tenta di scalare orizzontalmente l’applicazione. Se l’utente ha una sessione memorizzata sul Server A e la richiesta successiva viene gestita dal Server B, il Server B non troverà la sessione nel proprio database locale. Le soluzioni classiche a questo problema sono
- Sticky sessions: il load balancer instradata sempre lo stesso utente allo stesso server. Semplice, ma fragile
- Session store condiviso: tutte le istanze del server leggono le sessioni da un database centralizzato. Efficace, ma introduce un ulteriore punto di dipendenza
Questo approccio è ideale per applicazioni tradizionali con un’architettura monolitica, dove la scalabilità orizzontale non è una priorità critica, dove la revoca immediata delle sessioni è un requisito (es. applicazioni bancarie, sistemi con logout forzato), e dove si ha pieno controllo sull’infrastruttura backend.
JWT – JSON Web Tokens
I JSON Web Token (JWT) rappresentano un cambio di paradigma rispetto alle sessioni tradizionali. Invece di memorizzare lo stato sul server, l’intera informazione necessaria all’autenticazione viene codificata nel token stesso e affidata al client. Il server non conserva alcuna traccia delle sessioni attive, per validare una richiesta si limita a verificare la firma del token ricevuto. Questo approccio è definito stateless. Il flusso tipico di autenticazione con JWT è
- L’utente si autentica con username e password
- Il server verifica le credenziali e crea un JWT contenente le informazioni sull’utente (claims), ad esempio ID utente, ruoli, scadenza
- Il JWT viene firmato con una chiave segreta o una coppia di chiavi pubblica/privata
- Il token firmato viene restituito al client, che lo memorizza (localStorage, sessionStorage, o cookie)
- Ad ogni richiesta successiva, il client include il JWT nell’header HTTP (Authorization: Bearer <token>)
- Il server riceve il JWT, verifica la firma usando la propria chiave, controlla la scadenza e gli altri claims e, se tutto è valido, processa la richiesta senza accedere al database
Un JWT è composto da tre parti codificate in Base64URL e separate da punti
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikd1aWRvIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cHeader: specifica il tipo di token e l’algoritmo di firma
{
"alg": "HS256",
"typ": "JWT"
}Payload: contiene i claims, ovvero le informazioni sull’utente e sul token
{
"sub": "1234567890",
"name": "Mario Rossi",
"role": "admin",
"iat": 1716239000,
"exp": 1716242600
}I claims standard più importanti sono sub (subject, l’ID utente), iat (issued at, timestamp di emissione), exp (expiration, timestamp di scadenza), e iss (issuer, chi ha emesso il token)
Signature: il risultato della firma crittografica di header e payload
HMACSHA256(base64url(header) + "." + base64url(payload), secret)La firma garantisce l’integrità del token: se qualcuno modifica il payload (es. per cambiare il proprio ruolo da “user” ad “admin”), la firma non corrisponderà più e il server rifiuterà il token.
Attenzione: il payload di un JWT è solo codificato in Base64, non cifrato. Chiunque può decodificarlo e leggerne il contenuto quindi non inserire mai dati sensibili (password, numeri di carta di credito, ecc.) nel payload di un JWT.
Nella pratica, JWT viene solitamente implementato con una coppia di token
- Access Token: ha una breve durata (es. 15 minuti) e viene inviato ad ogni richiesta API. Se compromesso, il danno è limitato nel tempo
- Refresh Token: ha una lunga durata (es. 7-30 giorni) e viene usato esclusivamente per ottenere nuovi access token. Viene memorizzato in modo sicuro (cookie HttpOnly) e non viene inviato alle API
Questo approccio bilancia sicurezza e usabilità: l’utente non deve fare login ogni 15 minuti, ma un access token compromesso scade rapidamente. JWT è la scelta ideale per API RESTful, Single Page Application (SPA), architetture a microservizi e scenari di autenticazione cross-domain, dove diversi servizi devono autenticare le richieste in modo indipendente senza condividere un database di sessioni.
SSO – Single Sign-On
Immaginiamo tutte le applicazioni aziendali che utilizziamo in una giornata lavorativa, se per ognuna dovessimo avere un set di credenziali distinte per fare l’accesso tutto diventerebbe più complicato da gestire sia per l’utilizzatore finale che per gli amministratori di sistema. Il Single Sign-On risolve questo problema alla radice, un’unica autenticazione dà accesso a tutti i sistemi collegati.
Con SSO, l’identità dell’utente è gestita da un Identity Provider (IDP) centralizzato, ad esempio Google Workspace, Microsoft Azure AD, Okta o Keycloak e le applicazioni che si affidano all’IDP per l’autenticazione sono chiamate Service Provider (SP). Il flusso tipico è
- L’utente tenta di accedere a un’applicazione
- L’applicazione rileva che l’utente non è autenticato e lo reindirizza all’IDP
- L’IDP mostra la pagina di login (se l’utente non ha già una sessione SSO attiva)
- L’utente inserisce le proprie credenziali aziendali e l’IDP le verifica
- L’IDP crea una sessione SSO ed emette un token di autenticazione (spesso un SAML assertion o un token OpenID Connect)
- L’utente viene reindirizzato al Service Provider originale, con il token allegato
- Il Service Provider verifica il token con l’IDP e crea una sessione locale per l’utente
- Da questo momento, se l’utente accede a un’altra applicazione SSO, l’IDP riconosce la sessione SSO esistente e rilascia un nuovo token senza richiedere nuovamente le credenziali
SSO non è un singolo protocollo, ma un pattern implementabile in diversi modi
- SAML 2.0 (Security Assertion Markup Language): standard XML-based, molto diffuso in contesti enterprise. Verboso ma robusto e maturo
- OpenID Connect (OIDC): strato di identità costruito sopra OAuth 2.0 che usa JWT come formato dei token. Più moderno e adatto ad applicazioni web e mobili
- Kerberos: utilizzato principalmente in reti Windows/Active Directory per SSO interno all’organizzazione
SSO è la soluzione di riferimento per ambienti enterprise con molte applicazioni interne, suite di prodotti SaaS che vogliono offrire un’esperienza coerente ai propri utenti aziendali, organizzazioni soggette a requisiti di compliance che richiedono governance centralizzata degli accessi.
OAuth 2.0
Prima di analizzare OAuth, è essenziale chiarire un equivoco comune: OAuth 2.0 non è un protocollo di autenticazione, ma di autorizzazione. OAuth permette a un’applicazione di accedere a specifiche risorse di un utente su un altro servizio, senza che l’utente debba condividere le proprie credenziali con quella applicazione.
Il caso d’uso tipico: stai usando un’app di gestione dei social media e vuoi che pubblichi post su Twitter per tuo conto. Con OAuth, puoi autorizzare l’app ad accedere al tuo account Twitter senza mai condividere la tua password Twitter con l’app.
Una delle caratteristiche più potenti di OAuth è il sistema di scopes: l’utente può autorizzare l’applicazione ad accedere solo a specifiche risorse, limitando l’impatto di una potenziale compromissione. Ad esempio, un’applicazione che legge i tuoi contatti Google richiederà solo https://www.googleapis.com/auth/contacts.readonly, non accesso completo all’account. L’utente vede esattamente cosa sta autorizzando e può revocare singolarmente ogni autorizzazione.
OAuth è la scelta ideale quando si devono integrare servizi di terze parti, costruire API pubbliche con accesso controllato, abilitare scenari di tipo “Login con Google/GitHub” (tramite OIDC), o permettere ad applicazioni di terze parti di accedere ai dati della propria piattaforma.
OpenID Connect (OIDC)
OIDC è un protocollo di autenticazione costruito sopra OAuth 2.0. Aggiunge al flusso OAuth un ID Token, un JWT con claims standardizzati sull’identità dell’utente (nome, email, foto profilo, ecc.) e un endpoint /userinfo per ottenere informazioni aggiuntive. In pratica, OIDC risponde alla domanda a cui OAuth da solo non risponde: “Chi è l’utente?”
Un sistema SSO è spesso implementato tramite OIDC: l’IDP è allo stesso tempo un Authorization Server OAuth 2.0 e un OpenID Provider.
Conclusione
Sessioni, JWT, SSO e OAuth non sono in competizione tra loro: sono strumenti complementari, ciascuno progettato per rispondere a esigenze specifiche in contesti architetturali differenti.
- Le sessioni rimangono una soluzione valida e pragmatica per applicazioni tradizionali dove la semplicità e la revoca immediata sono prioritarie
- JWT ha rivoluzionato l’autenticazione per le API moderne, portando statelessness (assenza di stato) e scalabilità al costo di una maggiore complessità nella gestione del ciclo di vita dei token
- SSO ha trasformato la gestione degli accessi in ambienti enterprise, centralizzando governance e migliorando drasticamente l’esperienza utente
- OAuth ha reso possibile l’ecosistema delle API pubbliche e l’integrazione sicura tra servizi, diventando lo standard per l’autorizzazione delegata
