L’autenticazione è il controllo di chi effettua la richiesta; l’autorizzazione è la decisione, a ogni richiesta, su che cosa sia permesso fare. Nessun sistema sicuro può rinunciare a una delle due. L’albergo rende la cosa concreta: il documento alla reception è autenticazione; la tessera che apre la camera 412 – e soltanto la 412 – è autorizzazione. Sono domande diverse, poste in momenti diversi, risolte da macchinari diversi, e che falliscono in modi diversi – ed è per questo che i sistemi che le confondono rilasciano entrambi i tipi di violazione.
Punti chiave
| Domanda | Risposta |
|---|---|
| Autenticazione (AuthN) | Chi sta chiedendo? – credenziali → identità, una volta per sessione |
| Autorizzazione (AuthZ) | Che cosa è permesso fare? – politiche → consenti/nega, a ogni richiesta |
| I codici HTTP | 401 = non autenticato (un nome fuorviante) · 403 = identificato e rifiutato |
| La divisione dei protocolli | OIDC/SAML/passkey = authn · scope OAuth/RBAC/ACL = authz |
| La divisione dei fallimenti | AuthN fallisce come furto d’account · AuthZ come escalation di privilegi |
Come autenticazione e autorizzazione agiscono su una stessa richiesta
1 POST /login (credenziali + MFA) ── AUTENTICAZIONE, una volta sola
← token di sessione / cookie: identità stabilita
2 GET /documents/xKd91m ── ogni richiesta successiva:
a · token validato → identità ristabilita (meccanismo authn)
b · permesso valutato → ADA può leggere QUESTO documento? (decisione authz)
→ 200 entrambi superati
→ 401 token assente/non valido – challenge WWW-Authenticate; l'accesso risolve
→ 403 token valido, permesso negato – rifare l'accesso non cambia nulla
→ 404 alcune API nascondono del tutto gli oggetti vietati (RFC 9110 lo consente)
La stessa divisione nel codice applicativo – si accede una volta, si viene giudicati a ogni operazione:
// JavaScript / Node.js — Back4app JS SDK
// Authentication: once — who are you?
const user = await Parse.User.logIn('ada', password); // session token issued
// Authorization: every request — may YOU do THIS?
const doc = await new Parse.Query('Document').get('xKd91m');
// found if an ACL entry grants ada read · "not found" if not
doc.set('title', 'Renamed');
await doc.save(); // succeeds only if an entry grants ada WRITE // Flutter / Dart — Back4app Flutter SDK
// Authentication: once — who are you?
final user = ParseUser('ada', password, null);
await user.login(); // session token issued
// Authorization: every request — may YOU do THIS?
final response = await QueryBuilder<ParseObject>(ParseObject('Document'))
.query(); // returns only rows whose ACLs grant ada read
final doc = response.results!.first as ParseObject;
doc.set('title', 'Renamed');
await doc.save(); // succeeds only if an entry grants ada WRITE // iOS / Swift — Back4app Swift SDK
// Authentication: once — who are you?
let user = try await User.login(username: "ada", password: password)
// session token issued
// Authorization: every request — may YOU do THIS?
guard var doc = try await Document.query("objectId" == "xKd91m").first()
else { return } // found only if an ACL entry grants ada read
doc.title = "Renamed"
_ = try await doc.save() // succeeds only if an entry grants ada WRITE // Android / Kotlin — Back4app Android SDK
// Authentication: once — who are you?
val user = ParseUser.logIn("ada", password) // session token issued
// Authorization: every request — may YOU do THIS?
val doc = ParseQuery.getQuery<ParseObject>("Document").get("xKd91m")
// found if an ACL entry grants ada read · "not found" if not
doc.put("title", "Renamed")
doc.save() // succeeds only if an entry grants ada WRITE Autenticazione vs. autorizzazione, a confronto
| Autenticazione | Autorizzazione | |
|---|---|---|
| Domanda | Chi sta chiedendo? | Che cosa è permesso fare? |
| Ingressi | Credenziali: password, codici MFA, passkey, biometria | Politiche: ruoli, ACL, attributi, scope |
| Frequenza | Una volta per sessione (+ step-up per le azioni sensibili) | A ogni richiesta, per ogni oggetto |
| Produce | Una sessione o un token | Una decisione consenti/nega |
| Visibile all’utente | Sì – la schermata di accesso | Raramente – agisce in modo invisibile |
| Dove gira | Al confine: strato di identità, flusso di accesso | In profondità: strato applicativo e dei dati, accanto ai dati |
| Protocolli | OpenID Connect, SAML, WebAuthn | Scope OAuth 2.0, motori RBAC/ABAC/ReBAC |
| Token emblematico | ID token – chi si è autenticato | Access token – che cosa può fare chi lo porta |
| Fallisce come | Furto dell’account | Escalation di privilegi, esposizione di dati |
Due righe meritano la loro nota. Dove gira: l’autenticazione si concentra naturalmente al confine – un solo flusso di accesso, un solo provider di identità – mentre l’autorizzazione va collocata accanto ai dati che protegge, perché “questo utente può toccare questo oggetto?” ha bisogno dell’oggetto. Fallisce come: i modelli di minaccia sono disgiunti – il credential stuffing e il phishing attaccano l’autenticazione (ed è per questo che la MFA è la difesa authn con la leva più alta), mentre la broken object-level authorization guida le classifiche di sicurezza delle API come fallimento authz per eccellenza: utente autenticato, oggetto sbagliato, nessuno ha controllato.
401 e 403, con precisione
I codici di stato sono la distinzione vestita di numeri, e la RFC 9110 è esatta in proposito. 401 Unauthorized è il nome fuorviante più duraturo della storia: significa non autenticato – la richiesta “non porta credenziali di autenticazione valide”, la risposta deve recare un challenge WWW-Authenticate e presentare credenziali può risolvere. 403 Forbidden significa che il server ha capito esattamente chi stava chiedendo e rifiuta comunque – riautenticarsi è inutile per definizione. E la specifica benedice una terza mossa che i team di sicurezza adorano: rispondere 404 invece di 403, così che una risorsa vietata non confermi la propria esistenza. Azzeccare i codici non è pedanteria; i client costruiscono su di essi la logica di retry e di nuovo accesso, e un 403 che dovrebbe essere un 401 manda le persone contro un muro invece che verso un modulo di accesso.
OAuth, OIDC e l’eterna confusione
La confusione ha una risposta a forma di specifica. Il titolo di OAuth 2.0 è “The OAuth 2.0 Authorization Framework” – fa circolare permessi delimitati da scope, e la specifica OpenID Connect esiste proprio perché OAuth da solo “non è in grado di fornire informazioni sull’autenticazione di un utente finale”. OIDC aggiunge lo strato di identità: un ID token che afferma chi si è autenticato, distinto dall’access token che afferma che cosa può fare chi lo porta. Ogni pulsante “Accedi con…” è OIDC che fa autenticazione sopra l’impianto di autorizzazione di OAuth – un solo flusso, entrambi i concetti, ordinatamente sovrapposti invece che confusi.
I tre errori che arrivano in produzione
Autorizzazione nel client. Nascondere il pulsante di eliminazione è progettazione d’interfaccia; è il server a decidere se l’eliminazione viene eseguita, e quella è sicurezza. Secondo OWASP: negare per impostazione predefinita, applicare lato server e trattare i controlli nel client come semplici indizi di UX. Autenticato ≠ autorizzato. Verificare l’autenticazione ma non la proprietà dell’oggetto – /documents/42 servito a qualsiasi sessione valida – è la broken object-level authorization, la classe di vulnerabilità più comune nelle API. Il controllo va fatto per oggetto, per richiesta, senza eccezioni. Ordine dei middleware. Prima autenticare, poi autorizzare, nel codice come nel concetto: il middleware di identità stabilisce chi, poi gli handler chiedono se – e un controllo di autorizzazione che gira prima che l’identità sia stabilita autorizza in silenzio l’anonimo.
Casi d’uso tipici
- Accesso all’app + permessi sui dati – l’abbinamento di ogni giorno: un solo flusso di autenticazione, regole per oggetto su tutto quello che segue.
- Progettazione di API – semantica 401/403, token delimitati da scope e controlli a livello di oggetto come linguaggio d’errore del contratto.
- SaaS multi-tenant – autenticazione condivisa fra i tenant; autorizzazione confinata rigidamente dentro ciascuno.
- Strumenti di amministrazione e supporto – autenticazione step-up e autorizzazione elevata, deliberatamente eventi distinti.
- Contenuti pubblici + privati – la lettura anonima come regola di autorizzazione, prova che i due concetti funzionano in modo indipendente.
Quale controllo manca? Matrice decisionale
| Sintomo | Pezzo mancante |
|---|---|
| Chiunque abbia il link legge dati privati | Autorizzazione – controlli per oggetto |
| Le password rubate continuano a funzionare | Autenticazione – aggiungere la MFA |
| Dopo un errore di accesso si finisce contro muri 403 | Codice sbagliato – quel flusso è un 401 |
| Qualsiasi utente autenticato raggiunge le API di amministrazione | Autorizzazione – ruoli, negare per impostazione predefinita |
| ”Accedi con…” trattato come autorizzazione | Concetti mescolati – OIDC autentica; gli scope autorizzano |
| Pulsanti nascosti ma endpoint aperti | Autorizzazione applicata solo nel client |
Limiti e trade-off
- La divisione è concettuale, non sempre architetturale. Le app piccole fanno girare ragionevolmente entrambe in un unico stack di middleware; la disciplina sta nel tenere distinti i controlli, non i server.
- Un’authn forte non salva un’authz debole. Passkey e MFA verificano l’identità alla perfezione per un sistema che poi lascia leggere tutto a chiunque – i fallimenti sono indipendenti.
- L’autorizzazione a ogni richiesta ha un costo. Mettere in cache le decisioni, spingere le regole nello strato dei dati e indicizzare i permessi: così “controllare tutto” resta veloce.
- Lo step-up sfuma la cronologia. Le azioni sensibili riautenticano a metà sessione – l’autenticazione non è strettamente “una volta”, è “una volta per livello di garanzia”.
- La deriva del vocabolario causa bug reali. I team che dicono “auth” per entrambe le metà scrivono ticket, test e codici d’errore che le confondono; le parole sono la difesa più economica.
Autenticazione e autorizzazione su Back4app
Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. L’architettura della piattaforma è questa divisione: la classe User, le sessioni, il login social e l’adattatore MFA rispondono a chi sta chiedendo, producendo un token di sessione revocabile – e poi le ACL, i permessi a livello di classe e i ruoli rispondono a che cosa è permesso fare, valutati lato server su ogni richiesta REST, GraphQL e Live Query, esattamente come mostrano le schede di codice: si accede una volta, si viene giudicati a ogni operazione. La sezione sugli errori diventa strutturale: l’autorizzazione non può restare nel client perché Back4app la applica dietro l’API, gli oggetti non autorizzati tornano come non trovati invece di confermare la propria esistenza, e negare per impostazione predefinita è una casella da spuntare su una classe. Le due domande restano separate perché la piattaforma non le lascia mai fondersi.
Domande frequenti
Qual è la differenza tra autenticazione e autorizzazione, in parole semplici?
L'autenticazione verifica l'identità di chi sta chiedendo – credenziali, codici, biometria. L'autorizzazione decide che cosa quell'identità può fare – ruoli, permessi, politiche. Versione albergo: mostrare un documento alla reception è autenticazione; la tessera che apre la camera assegnata ma non la suite è autorizzazione.
Quale viene prima, l'autenticazione o l'autorizzazione?
L'autenticazione, quasi sempre – un sistema non può concedere permessi a uno sconosciuto. L'eccezione istruttiva: le risorse pubbliche sono decisioni di autorizzazione prese senza autenticazione; "chiunque può leggere questo" resta una regola di permesso, applicata all'anonimo.
Qual è la differenza tra un errore 401 e un errore 403?
401 significa che la richiesta non porta credenziali di autenticazione valide – nonostante il nome ufficiale "Unauthorized", vuol dire non autenticato, e l'accesso può risolvere. 403 significa che il server sa esattamente chi sta chiedendo e rifiuta comunque – permesso negato, e rifare l'accesso non cambia nulla.
Può esistere autorizzazione senza autenticazione?
Sì – ogni endpoint pubblico ne è la prova: l'accesso anonimo è una regola di autorizzazione valutata senza identità. Esiste anche il contrario: autenticati ma autorizzati a nulla, che è esattamente ciò che dovrebbe essere un account appena creato e senza ruoli.
Quali protocolli gestiscono l'autenticazione e quali l'autorizzazione?
Autenticazione: password, MFA, passkey e WebAuthn, sessioni, OpenID Connect, SAML. Autorizzazione: ruoli (RBAC), regole per attributi (ABAC), ACL, scope OAuth 2.0, motori di politiche. OAuth sta notoriamente dal lato dell'autorizzazione – la sua fama di meccanismo di accesso viene da OpenID Connect, che gli si innesta sopra.
OAuth è autenticazione o autorizzazione?
Autorizzazione – il titolo stesso della specifica è "The OAuth 2.0 Authorization Framework", e la specifica OpenID Connect esiste proprio perché OAuth da solo non può attestare chi si è autenticato. Ogni vero pulsante "Accedi con…" è OIDC che aggiunge uno strato di identità sopra l'impianto di OAuth.
Come lavorano insieme autenticazione e autorizzazione in una richiesta?
Si autentica una volta sola all'accesso, producendo una sessione o un token. Poi, a ogni richiesta, il server ristabilisce l'identità da quel token e valuta l'autorizzazione per la risorsa e l'azione precise. Una volta per sessione contro ogni singola richiesta – quell'asimmetria è tutta l'architettura.
Quali sono gli errori più comuni?
Confondere le due cose nella gestione degli errori (un 403 dove serve un 401), applicare l'autorizzazione nel client (nascondere i pulsanti è UX, non sicurezza) e verificare che un utente sia autenticato ma non che possieda l'oggetto preciso – la falla della broken object-level authorization che guida le classifiche di sicurezza delle API.