Le chiavi di API e OAuth risolvono problemi diversi, e la scelta fra i due parte da una sola domanda: c'è una terza parte nello schema?

Se il vostro server chiama l'API di qualcun altro a proprio nome, serve una chiave. Se l'applicazione di qualcun altro chiama la vostra API per conto del vostro utente, serve OAuth. Senza una terza parte in gioco, OAuth aggiunge cerimoniale e non sicurezza.

Di seguito: in cosa differiscono davvero, cosa è cambiato in OAuth negli ultimi anni e una proprietà delle chiavi di API di cui quasi nessuno scrive, benché sia proprio quella a stabilire come ci convivrete in produzione.

La chiave di API: una stringa che dice «questo programma può»

Una chiave è una lunga stringa casuale che mettete in un'intestazione della richiesta:

X-Api-Key: lix_live_9f2c...

Il server trova la chiave, capisce a quale account appartiene e lascia passare la richiesta. Il meccanismo finisce qui.

Le proprietà che ne discendono:

  • una chiave non scade da sola. Vive finché qualcuno non la revoca;
  • una chiave identifica un programma, non una persona. Chi del team abbia fatto la chiamata di solito non si vede;
  • una chiave concede tutto ciò che l'account può fare, a meno che non ne restringiate i diritti a parte;
  • la chiave è l'unico segreto. Se trapela, trapela l'accesso: non ci sono passaggi intermedi.

OAuth: un protocollo sul consenso

OAuth 2.0 (RFC 6749) risponde a un'altra domanda. Ha quattro partecipanti: il proprietario dei dati, l'applicazione che li vuole, un server di autorizzazione e il server che custodisce i dati.

Il percorso è più o meno questo. L'applicazione manda la persona sulla pagina del servizio stesso. Lì vede chi chiede e per cosa, e acconsente. L'applicazione riceve un codice, lo scambia con un token di accesso e con quello chiama l'API. Il token vive poco — minuti oppure ore; quando scade, l'applicazione scambia un token di aggiornamento con uno nuovo.

Ciò che questo porta e che una chiave non può portare per costruzione:

  • la password dell'utente non arriva mai all'applicazione. Il senso sta tutto qui;
  • i permessi si spezzano in ambiti. «Leggere i link» e «cancellare i link» sono concessioni distinte;
  • il consenso è visibile e revocabile. L'utente vede l'elenco delle applicazioni collegate e può scollegarne una senza toccare le altre;
  • i token scadono da soli. Un token di accesso rubato non vale nulla un'ora dopo.

Il prezzo è la complessità: un server di autorizzazione, la registrazione delle applicazioni, una schermata di consenso, conservazione e rotazione dei token di aggiornamento e la gestione della scadenza a ogni chiamata.

Confronto lungo gli assi che decidono davvero

Chiave di API OAuth 2.0
Chi attesta il programma l'utente per conto del quale il programma agisce
Durata indefinita token di accesso: minuti o ore
Come finisce l'accesso revocare la chiave revocare il consenso o il token
Ampiezza dei diritti di norma l'intero account ambiti per singola azione
Segreto in mano alla terza parte la chiave stessa solo token, mai la password
Sforzo di integrazione un'intestazione un server di autorizzazione e l'intero ciclo
Dove si colloca server a server, script, integrazioni interne app pubbliche, marketplace, «Accedi con…»

La regola per scegliere

La domanda non è quale sia più sicuro in astratto, ma chi delega l'accesso a chi.

Il vostro server → API altrui, account vostro
    → chiave di API

App altrui → la vostra API, account del vostro utente
    → OAuth

Processo pianificato, CI, integrazione di backend
    → chiave di API

L'utente deve vedere e revocare l'accesso applicazione per applicazione
    → OAuth

Ricevere postback è il caso da manuale per una chiave. Quando il vostro server comunica al nostro che un ordine è stato pagato, in quello scambio non c'è nessun utente, non c'è chi possa acconsentire né dove collocare una schermata di consenso. Lo stesso vale per i webhook nella direzione opposta.

Cosa è cambiato in OAuth mentre guardavate altrove

Metà degli articoli sull'argomento descrive OAuth com'era nel 2015. Da allora si è ristretto parecchio.

Nel gennaio 2025 l'IETF ha pubblicato la RFC 9700, Best Current Practice for OAuth 2.0 Security. Il documento raccoglie anni di esperienza con attacchi reali e dichiara formalmente superati due flussi che prima erano ritenuti accettabili:

  • l'implicit grant, quello che restituiva il token direttamente nella barra degli indirizzi;
  • resource owner password credentials, in cui l'applicazione chiedeva all'utente nome utente e password. Esattamente ciò che OAuth doveva eliminare.

Nello stesso movimento PKCE è diventato obbligatorio per tutti i tipi di client, compresi quelli lato server, e non più solo per il mobile.

Vale la pena saperlo a parte: OAuth 2.1 è tuttora una bozza, non una RFC pubblicata. Raccoglie le stesse modifiche in un unico documento — PKCE obbligatorio, confronto esatto della redirect URI, niente implicit né password grant, niente token nella stringa di query. Citarlo come standard vigente è prematuro.

Conseguenza pratica: se una guida a OAuth propone il flusso implicito, quella guida è invecchiata.

Il punto debole delle chiavi di cui si parla poco

Una chiave non scade. Questo rende la revoca la vostra unica leva. Ed è qui che spunta il fastidio: la revoca di solito non è immediata.

Verificare la chiave a ogni richiesta significa interrogare la base di dati. Su qualsiasi API con traffico reale quel risultato viene messo in cache. Da noi la corrispondenza fra chiave e account resta in cache cinque minuti. Fra il clic su «revoca» e l'effettiva interruzione dell'accesso passano quindi fino a cinque minuti, durante i quali una chiave compromessa continua a funzionare.

Non è una svista, è uno scambio: senza cache ogni richiesta bussa alla base di dati. Quasi tutte le API basate su chiavi accettano un patto simile, solo che non si usa dirlo ad alta voce. Conta per due motivi. Primo: in una fuga reale revocare la chiave è la prima mossa e non l'ultima, perché subito dopo occorre controllare cosa è successo in quei minuti. Secondo: è esattamente il problema che i token a vita breve di OAuth affrontano dall'altro capo — scadono da soli, senza coinvolgere alcuna base di dati.

Convivere con le chiavi senza farsi male

Se le chiavi bastano — e nella maggior parte delle integrazioni bastano — il minimo è questo:

  1. Conservate solo l'impronta. Il server confronta l'impronta della chiave presentata con quella memorizzata; la stringa originale si mostra una volta sola, alla creazione. Le nostre si verificano in SHA-256.
  2. Date un prefisso alla chiave. Una stringa nella forma lix_live_... viene riconosciuta dagli scanner di segreti nei repository e nelle pipeline di log.
  3. Una chiave per ogni integrazione. Così revocarne una non abbatte le altre, e dal registro si vede esattamente cosa è stato compromesso.
  4. Non mettete mai la chiave nella stringa di query. Gli indirizzi finiscono nei log del server web, nell'intestazione Referer e nella cronologia del browser. Solo intestazione.
  5. Ruotate a calendario, non dopo un incidente. Una chiave già ruotata una volta si ruota in fretta. Una mai ruotata si scoprirà scritta a mano in quattro punti.
  6. Guardate la data di ultimo utilizzo. Una chiave intoccata da sei mesi non è una scorta, è una porta aperta.

Cosa usiamo noi

L'API di Lix.li si autentica con chiavi: intestazione X-Api-Key, chiavi create e revocate dal pannello, verifica per impronta, limite di richieste separato per ciascuna chiave. OAuth non c'è, ed è una scelta: gli scenari dell'API stanno lato server — creare un link, recuperare statistiche, accettare una conversione — e in nessuno di essi compare una terza parte a cui l'utente debba dare il consenso.

Se nascesse l'esigenza di far entrare applicazioni altrui negli account dei nostri clienti, le chiavi non basterebbero più: l'utente deve poter vedere a chi ha permesso cosa e scollegare una singola applicazione senza rompere le altre. È lì che OAuth smette di essere cerimoniale e diventa l'unica opzione onesta.

Le chiamate vere e proprie sono descritte nella documentazione dell'API, compresi i codici di risposta che tornano con una chiave non valida e con una revocata. Due temi vicini meritano un approfondimento a parte: i webhook, se preferite ricevere gli eventi invece di interrogarli, e la differenza fra i redirect 301, 302, 307 e 308 — perché un 301 trasforma un POST in GET, cosa che tocca direttamente la ricezione dei postback.