Laravel Sanctum e Passport: scegliere l'autenticazione API giusta per una PMI

Laravel Sanctum e Passport: scegliere l'autenticazione API giusta per una PMI

Quando una PMI deve esporre un'API, a un'app mobile propria o a qualche partner B2B, in Laravel la domanda arriva puntuale: Sanctum o Passport? E quasi sempre arriva con il pregiudizio sbagliato, quello per cui "OAuth suona più professionale, quindi Passport". È l'errore che porta a montare un server OAuth2 completo per autenticare l'app del proprio negozio, con tutta la complessità e la superficie d'attacco che ne consegue, quando sarebbero bastate poche righe. La scelta tra i due non è una questione di moda né di prestigio, è una questione di requisiti: chi sono i client, li controlli tu o sono terze parti, ti serve davvero il flusso di consenso di OAuth o ti serve solo un token. In una piattaforma con migliaia di utenti attivi ho visto entrambe le derive, Passport montato dove bastava Sanctum e, più raramente, Sanctum forzato dove serviva un vero provider OAuth. Vediamo le differenze reali tra i due, una tabella decisionale che taglia corto, e i casi in cui ciascuno è la scelta giusta, senza prendere la più complessa per default.

I due strumenti, in una frase ciascuno

La distinzione di fondo è semplice e va fissata prima di ogni altra considerazione. Sanctum è un sistema di autenticazione leggero: gestisce l'autenticazione di una SPA o di un'app mobile tramite cookie di sessione, e l'emissione di API token semplici (bearer token) per i client. Niente flussi OAuth, niente schermate di consenso: emetti un token, lo usi, lo revochi. Passport è invece un'implementazione completa di un server OAuth2: gestisce client registrati, flussi di authorization code, scope, token di refresh, schermate di autorizzazione. È l'infrastruttura che useresti se volessi permettere a sviluppatori terzi di costruire applicazioni che si autenticano contro il tuo servizio, come fanno "accedi con Google" o "accedi con GitHub".

Detto in altri termini: Sanctum risponde alla domanda "come do un token alla mia app?", Passport risponde alla domanda "come divento un provider di identità per applicazioni che non controllo?". Sono due domande diverse, e la maggior parte delle PMI si pone solo la prima. Non a caso Sanctum è oggi il sistema di autenticazione API di default in Laravel, mentre Passport resta lo strumento specializzato per OAuth2.

La tabella decisionale, senza giri di parole

Messe una accanto all'altra, le differenze che contano per una decisione sono queste:

CriterioSanctumPassport
Tipo di soluzioneToken semplici + auth SPA via cookieServer OAuth2 completo
ComplessitàBassa, poche righeAlta, molte parti mobili
Client tipiciApp e SPA tue (first-party)App di terze parti che non controlli
Flusso di consensoNoSì (authorization code, schermate)
Scope / abilityAbility semplici sui tokenScope OAuth granulari
Token di refreshNo (token a revoca)
Caso d'usoApp mobile propria, SPA, API per pochi partnerDiventare provider OAuth per ecosistemi di terzi
Overhead di manutenzioneMinimoSignificativo (chiavi, client, token store)

La tabella dice una cosa sola, ma la dice chiara: Sanctum è la scelta di default per il caso comune, Passport è lo strumento specializzato per un requisito specifico e meno frequente. Tutto il resto è conseguenza di questa asimmetria.

Se stai progettando l'API di un'applicazione e non sei sicuro di quale dei due ti serva davvero, nel mio profilo professionale trovi l'esperienza concreta su architetture API e autenticazione per piattaforme reali, dove la scelta giusta è quasi sempre la più semplice che soddisfa i requisiti.

Quando Sanctum è la scelta giusta (quasi sempre, per una PMI)

Sanctum copre, nella mia esperienza, l'ottanta per cento abbondante dei casi di una PMI. Se hai un'app mobile tua che parla con il tuo backend, Sanctum emette un token all'utente che fa login e quel token autentica le chiamate successive: fine, è tutto ciò che serve. Se hai una single page application servita dallo stesso dominio del backend, Sanctum gestisce l'autenticazione via cookie di sessione con protezione CSRF, senza nemmeno bisogno di token. Se devi dare accesso programmatico alla tua API a qualche partner B2B, emetti per ciascuno un API token con le ability che gli competono e lo revochi quando il rapporto finisce.

// emissione di un token con ability mirate per un partner B2B
$token = $user->createToken('partner-acme', ['orders:read', 'invoices:read']);
return ['token' => $token->plainTextToken];

// nel controller, si verifica l'ability
if ($request->user()->tokenCan('orders:read')) { /* ... */ }

Vale la pena conoscere una sfumatura interna a Sanctum, perché evita un errore comune: Sanctum ha due modalità distinte, e vanno usate nel contesto giusto. Per una SPA servita dallo stesso dominio del backend, la modalità corretta è l'autenticazione via cookie di sessione, con protezione CSRF, che non richiede di maneggiare token nel frontend ed è più sicura perché il token non è mai esposto al JavaScript. Per un'app mobile o per un client su un dominio diverso, dove i cookie non sono praticabili, si usa invece l'API token come bearer. Scegliere la modalità sbagliata, per esempio gestire a mano i token in una SPA same-domain quando basterebbe il cookie, è una complicazione inutile che apre anche a errori di sicurezza. La regola è: stesso dominio, cookie di sessione; dominio diverso o app nativa, token. Sanctum copre entrambi, ma con strumenti diversi.

Il punto di forza di Sanctum è che fa esattamente questo e niente di più. Non c'è un server OAuth da mantenere, non ci sono chiavi di firma da ruotare, non ci sono client da registrare. La superficie d'attacco è ridotta perché le parti mobili sono poche, e questo è un vantaggio di sicurezza, non solo di comodità. Per un'API REST di un gestionale, l'approccio Sanctum è quello che raccomando per impostazione predefinita, ed è coerente con le pratiche che ho descritto parlando di sicurezza delle API REST per gestionali Laravel.

Quando serve davvero Passport

Passport non è "Sanctum con più funzioni", è uno strumento per un problema diverso, e ha senso solo quando quel problema è il tuo. Il caso d'uso reale è uno: vuoi diventare un provider OAuth2 per applicazioni di terze parti che non controlli. Se stai costruendo una piattaforma su cui sviluppatori esterni registrano le loro applicazioni e i tuoi utenti devono poter autorizzare quelle applicazioni ad accedere ai loro dati, con una schermata di consenso e scope granulari che l'utente approva, allora ti serve un vero server OAuth2, e Passport te lo dà già pronto. È lo scenario di chi costruisce un ecosistema, non di chi espone un'API per uso interno.

In questo caso valgono alcune accortezze recenti. Con le versioni moderne di Laravel, Passport va aggiornato alla linea 12.x, le sue migrazioni vanno pubblicate esplicitamente nell'applicazione, e soprattutto il password grant è disabilitato di default: è una scelta di sicurezza, perché quel flusso è sconsigliato, e va riabilitato consapevolmente solo se hai un motivo preciso. Proprio perché OAuth2 ha molte più parti mobili, ha anche più modi di essere implementato male: gli errori di configurazione di un flusso OAuth sono una categoria di vulnerabilità a sé, che ho trattato parlando di vulnerabilità OAuth2 nell'implementazione di API Laravel. Montare Passport significa accollarsi quella responsabilità: ha senso quando il requisito lo giustifica, è un rischio gratuito quando non lo fa.

La sicurezza dei token, che vale per entrambi

Qualunque dei due scegli, alcuni principi di sicurezza dei token non cambiano, e sono quelli che separano un'API solida da una colabrodo. I token vanno conservati come hash nel database, mai in chiaro, così che un accesso al database non riveli i token attivi; sia Sanctum che Passport lo fanno, ma è bene saperlo. I token devono avere un perimetro: le ability di Sanctum o gli scope di Passport servono a dare a ogni token solo i permessi che gli competono, applicando il least privilege anche all'autenticazione. Devono avere una scadenza e una via di revoca, perché un token che non scade e non si può revocare è una chiave universale persa. E non devono mai finire dove possono essere intercettati: mai un token in un URL, mai in un log, sempre e solo sotto HTTPS, nell'header Authorization. La rotazione delle credenziali, che ho approfondito parlando di rotazione delle chiavi e rehashing in Laravel, completa il quadro: un token, come una password, ha un ciclo di vita che va gestito, non lasciato a sé stesso.

Il ciclo di vita dei token: scadenza, refresh e macchina-a-macchina

Una differenza pratica che pesa sulla scelta riguarda il ciclo di vita dei token. I token di Sanctum, di default, non scadono: restano validi finché non li revochi. Per molti scenari va bene, ma per altri è un rischio, e va gestito impostando una scadenza esplicita nella configurazione di Sanctum e affidandosi alla revoca per il resto. Passport, essendo OAuth2, porta invece nativamente i refresh token: token di accesso a vita breve che si rinnovano con un token di refresh a vita più lunga, un meccanismo più sofisticato ma anche più complesso da gestire correttamente. La domanda da farsi è se il tuo caso ha davvero bisogno di quel meccanismo o se la coppia "token a scadenza più revoca" di Sanctum è sufficiente: nella maggior parte dei casi lo è.

La sofisticazione di un meccanismo di autenticazione non è un valore in sé. Un refresh token gestito male è meno sicuro di un token semplice gestito bene. La domanda giusta non è "quale meccanismo è più avanzato", è "quale riesco a far funzionare correttamente con le competenze e il tempo che ho".

C'è poi il caso machine-to-machine, due sistemi che si parlano senza un utente umano nel mezzo, tipico delle integrazioni B2B. Anche qui la risposta semplice di solito vince: un API token di Sanctum, emesso per il sistema partner con le ability che gli competono, copre il caso senza scomodare il flusso client credentials di OAuth. Si sale a Passport solo se il numero di integrazioni di terze parti e la necessità di una gestione self-service dei client lo giustificano, non perché "macchina-a-macchina suona come OAuth".

Sanctum o Passport per un'app mobile?

La risposta, nel novantanove per cento dei casi, è Sanctum. Un'app mobile che tu sviluppi e distribuisci è un client first-party: la controlli tu, non è un'applicazione di terze parti che deve chiedere il consenso dell'utente per accedere ai suoi dati su una piattaforma altrui. Quello è precisamente lo scenario per cui OAuth2 esiste, ed è precisamente lo scenario che la tua app mobile non è. Usare Passport per la tua app significa pagare la complessità di un flusso di consenso e di un server OAuth per risolvere un problema, "dai un token al mio utente che fa login", che Sanctum risolve in modo diretto. L'unica eccezione è se la tua app deve integrarsi come client OAuth verso un provider esterno, ma quello è un problema diverso, ed è il provider esterno ad avere il server OAuth, non tu.

L'errore che costa: l'over-engineering per default

Concludo sul punto che è la vera ragione di questo articolo. La tentazione di scegliere Passport "per stare larghi" o "perché è più completo" è la versione autenticazione di un anti-pattern più generale: scegliere la soluzione complessa per default, nella convinzione errata che più infrastruttura significhi più solidità. È il contrario. Ogni parte mobile in più di un server OAuth, le chiavi, i client, i token di refresh, le schermate di consenso, è una cosa in più che va configurata, mantenuta, aggiornata e messa in sicurezza, ed è una superficie d'attacco in più. Per un requisito che Sanctum soddisfa, Passport non aggiunge robustezza, aggiunge fragilità e costo di manutenzione.

La regola che applico è una sola, e vale ben oltre l'autenticazione: si sceglie lo strumento più semplice che soddisfa i requisiti reali, e si sale di complessità solo quando un requisito concreto lo impone. Per la maggior parte delle PMI che espongono un'API a un'app propria o a pochi partner, quello strumento è Sanctum, e sceglierlo non è "accontentarsi", è progettare bene. Passport resta lì, pronto, per il giorno in cui diventerai un provider di identità per un ecosistema di terzi: quel giorno lo monterai con cognizione di causa, sapendo perché ti serve. Se stai progettando l'API della tua applicazione e vuoi essere sicuro di non costruire un'infrastruttura più complessa di quanto il tuo caso richieda, oppure se hai un server OAuth montato dove bastava un token e vuoi semplificare, contattami per una consulenza diretta: nella mia esperienza, la scelta di autenticazione giusta è quasi sempre quella che ti lascia meno cose da sorvegliare, meno parti che si possono rompere nel tempo e meno superficie esposta che un attaccante può andare a colpire.

Ultima modifica: