OAuth 2.1 non è, al 1 ottobre 2026, uno standard IETF definitivo. Il documento corrente è draft-ietf-oauth-v2-1-16, pubblicato il 3 settembre 2026. Il confronto con OAuth 2.0 resta però utile perché il draft raccoglie in un unico framework molte correzioni di sicurezza maturate dopo RFC 6749, tra PKCE, OAuth Security Best Current Practice e indicazioni specifiche per applicazioni native e browser.

Per un developer la differenza più importante non è il numero di versione. È capire quali pattern del vecchio OAuth 2.0 non dovrebbero più entrare in un progetto nuovo e quali controlli sono già considerati best practice oggi, anche quando il provider dichiara ancora supporto a OAuth 2.0.

OAuth 2.0 e OAuth 2.1 a colpo d'occhio

Aspetto OAuth 2.0 originale OAuth 2.1 draft
Authorization Code previsto senza PKCE nel core PKCE integrato nel flusso standard
PKCE plain definito da RFC 7636 rimosso, si usa S256
Implicit Grant previsto omesso
Resource Owner Password Credentials previsto omesso
Redirect URI regole originarie meno restrittive confronto esatto della URI registrata
Refresh token per public client il core è poco prescrittivo sender-constrained oppure one-time use
Bearer token nella query string previsto da RFC 6750 omesso
redirect_uri al token endpoint usato nel code flow OAuth 2.0 rimosso dal flusso OAuth 2.1

Questa tabella non significa che un'implementazione OAuth 2.0 moderna debba usare i comportamenti della colonna sinistra. RFC 9700, pubblicato nel gennaio 2025 come Best Current Practice, ha già deprecato diversi pattern storici e introdotto requisiti più severi. OAuth 2.1 li consolida nel framework.

OAuth 2.1 non riparte da zero

OAuth 2.0 nasce con RFC 6749 nel 2012. Negli anni il protocollo è stato esteso da specifiche separate: PKCE con RFC 7636, le indicazioni per native app con RFC 8252, le best practice di sicurezza con RFC 9700 e, più recentemente, le indicazioni per browser-based application con RFC 10017.

Il draft OAuth 2.1 cerca di ridurre questa frammentazione. La sezione dedicata alle differenze dichiara esplicitamente che il nuovo testo consolida OAuth 2.0, Bearer Token Usage, PKCE, OAuth for Native Apps, OAuth Security BCP e il lavoro sulle applicazioni browser.

Questo ha un effetto pratico: molti comportamenti che in OAuth 2.0 risultavano possibili ma sconsigliati spariscono dal framework principale.

PKCE entra nel flusso Authorization Code

PKCE, Proof Key for Code Exchange, nasce per impedire che un authorization code intercettato possa essere riutilizzato da un client diverso da quello che ha iniziato la richiesta.

Il client genera un code_verifier casuale e ne calcola un digest SHA-256, inviato all'authorization endpoint come code_challenge. Quando scambia il codice con un token, presenta il verifier originale. Il server può così verificare che chi sta usando il codice sia lo stesso client che aveva avviato il flusso.

In OAuth 2.1 questi parametri fanno parte del modo standard di usare Authorization Code. Il metodo PKCE plain, che non offriva protezione contro alcuni scenari di intercettazione, viene escluso. Rimane S256.

Un esempio browser in JavaScript:

function base64url(bytes) {
  return btoa(String.fromCharCode(...bytes))
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");
}

const random = new Uint8Array(32);
crypto.getRandomValues(random);
const codeVerifier = base64url(random);

const digest = await crypto.subtle.digest(
  "SHA-256",
  new TextEncoder().encode(codeVerifier)
);

const codeChallenge = base64url(new Uint8Array(digest));

La richiesta di autorizzazione può quindi includere:

GET /authorize?
  response_type=code&
  client_id=my-client&
  redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&
  scope=openid%20profile&
  state=RANDOM_STATE&
  code_challenge=PKCE_CHALLENGE&
  code_challenge_method=S256

Al token endpoint il client invia il codice ricevuto insieme al code_verifier:

const response = await fetch("https://auth.example.com/token", {
  method: "POST",
  headers: {
    "Content-Type": "application/x-www-form-urlencoded"
  },
  body: new URLSearchParams({
    grant_type: "authorization_code",
    client_id: "my-client",
    code,
    code_verifier: codeVerifier
  })
});

Per un confidential client restano applicabili i meccanismi di autenticazione del client previsti dal server. PKCE non sostituisce l'autenticazione del client: protegge l'authorization code da intercettazione e injection.

L'Implicit Grant scompare

RFC 6749 definiva l'Implicit Grant per client che ricevevano direttamente l'access token nella risposta dell'authorization endpoint. Era particolarmente comune nelle vecchie single-page application, quando il browser non aveva ancora le capacità e i pattern oggi disponibili.

OAuth 2.1 omette response_type=token. RFC 9700 aveva già deprecato l'Implicit Grant perché l'access token esposto nel front channel è più difficile da proteggere da leakage e injection, oltre a non poter essere sender-constrained nello stesso modo.

Per una SPA moderna il riferimento aggiornato è RFC 10017, pubblicato nell'agosto 2026. Il documento indica Authorization Code con PKCE come base per le browser-based application e analizza anche architetture con componente server-side, come il Backend for Frontend, quando il modello di rischio richiede di evitare che i token siano direttamente accessibili al codice JavaScript.

Questo non significa che ogni SPA debba avere un BFF. Significa che la scelta dell'architettura deve considerare dove vivono access token e refresh token, quali capacità ha un eventuale XSS e quali proprietà di sicurezza offre il backend.

Resource Owner Password Credentials non c'è più

Il Resource Owner Password Credentials grant, spesso abbreviato ROPC o password grant, permetteva al client di raccogliere username e password dell'utente e scambiarli direttamente con un access token.

È un modello in conflitto con una delle proprietà più utili di OAuth: il client non dovrebbe conoscere le credenziali dell'utente. Inoltre rende difficile integrare correttamente MFA, autenticazione federata, passkey e altri meccanismi gestiti dall'authorization server.

OAuth 2.1 omette completamente questo grant, in linea con RFC 9700.

Se un'applicazione nuova sta ancora progettando un form che raccoglie la password per poi chiamare il token endpoint con grant_type=password, il problema non è la compatibilità con OAuth 2.1. È il modello di autenticazione che va ripensato.

Redirect URI: il confronto deve essere esatto

Le redirect URI sono uno dei confini di sicurezza del protocollo. Un authorization code inviato a una destinazione controllata da un attaccante può trasformare un errore di configurazione in furto di credenziali OAuth.

RFC 9700 richiede exact string matching tra la URI ricevuta e quella registrata, con l'eccezione prevista per le porte dinamiche dei loopback redirect nelle native app. OAuth 2.1 incorpora questa regola.

Configurazioni permissive come:

https://app.example.com/*

o controlli basati soltanto sul dominio non corrispondono al modello indicato dalla BCP.

Il redirect dovrebbe essere registrato nella sua forma precisa:

https://app.example.com/oauth/callback

La stessa area merita attenzione anche per gli open redirector. Un endpoint del client che accetta una destinazione arbitraria può diventare parte di una catena che porta alla perdita del codice o del token.

Cambia anche la gestione dei refresh token

Per i public client un refresh token è una credenziale particolarmente sensibile: se viene copiato, il solo possesso può permettere di ottenere nuovi access token per un periodo molto più lungo della vita del token originale.

OAuth 2.1 recepisce la regola di RFC 9700 secondo cui i refresh token dei public client devono essere sender-constrained oppure one-time use. Nel secondo caso, la rotazione consente all'authorization server di rilevare il riuso di un refresh token già consumato.

È un punto che interessa direttamente applicazioni native e browser client che non possono custodire un client secret come farebbe un backend.

Il tema dei token OAuth non è teorico. Nell'analisi del breach Vercel del 2026 abbiamo visto come token e grant concessi a servizi terzi possano diventare credenziali ad alto valore quando il sistema che li conserva viene compromesso.

Bearer token nella query string: fuori dal framework

RFC 6750 prevedeva anche la possibilità di inviare un bearer token nella query string. OAuth 2.1 omette questo metodo, seguendo RFC 9700.

Una richiesta come:

GET /api/profile?access_token=eyJ...

espone il token a superfici che un header Authorization evita: URL salvati nella cronologia, log di reverse proxy e web server, strumenti di analytics, referrer e altri sistemi che trattano l'URL come dato osservabile.

L'uso normale resta:

Authorization: Bearer eyJ...

Anche qui la differenza tra OAuth 2.0 e 2.1 non richiede di aspettare il nuovo framework. È già una pratica da adottare nelle implementazioni correnti.

Il redirect_uri non viene più inviato al token endpoint

C'è una differenza meno nota ma utile quando si confrontano implementazioni.

Nel code flow OAuth 2.0 il token request può includere redirect_uri, e RFC 6749 lo rende necessario in determinate condizioni. Nel draft OAuth 2.1 il parametro è rimosso dal token request perché il legame della transazione viene protetto da code_challenge e code_verifier.

Il draft contiene però una regola esplicita di compatibilità: un authorization server che supporta sia client OAuth 2.0 sia OAuth 2.1 deve continuare ad accettare il parametro dai client legacy e applicare le regole di RFC 6749.

Questa è una delle ragioni per cui non conviene implementare OAuth copiando alla lettera una singola richiesta vista in un tutorial. Il comportamento corretto dipende dalla versione e dal profilo supportato dall'authorization server.

OAuth 2.1 non sostituisce OpenID Connect

OAuth regola l'autorizzazione a risorse protette. Non definisce da solo un protocollo di login che permetta al client di stabilire l'identità dell'utente.

Per autenticazione federata si usa normalmente OpenID Connect, costruito sopra OAuth. Un access_token dice che il client può accedere a determinate risorse; non dovrebbe essere interpretato arbitrariamente come prova dell'identità dell'utente.

Questa distinzione resta valida con OAuth 2.1. Cambia il framework di autorizzazione, non la separazione concettuale tra OAuth e OpenID Connect.

La protezione da CSRF e dagli attacchi sul redirect flow resta inoltre parte del modello applicativo. La guida f-hack su CSRF approfondisce il problema dal punto di vista delle applicazioni web; RFC 9700 descrive invece come state, PKCE e nonce entrino nel contesto OAuth e OpenID Connect.

Cosa usare in un progetto nuovo nel 2026

Non serve aspettare che OAuth 2.1 diventi RFC per smettere di usare pattern già deprecati.

Per un nuovo progetto, il profilo di partenza dovrebbe includere Authorization Code con PKCE S256, redirect URI registrate con corrispondenza esatta, nessun Implicit Grant, nessun password grant e bearer token nell'header Authorization.

Per i public client va affrontata esplicitamente la gestione dei refresh token. Per le applicazioni browser conviene leggere RFC 10017 prima di decidere se i token saranno gestiti interamente nel browser oppure mediati da un backend.

Un authorization server moderno dovrebbe inoltre esporre metadata standard, mentre nei contesti con requisiti più elevati possono entrare in gioco meccanismi come DPoP o mutual TLS per sender-constrain degli access token.

Non tutto ciò è esclusivo di OAuth 2.1. È proprio questo il punto: buona parte del percorso verso 2.1 consiste nell'applicare correttamente le specifiche e le BCP che hanno corretto OAuth 2.0 negli anni.

Migrare un'implementazione OAuth 2.0 esistente

La prima verifica utile non è cercare una voce "OAuth 2.1" nel pannello del provider. Conviene inventariare i flow realmente usati.

Se esiste response_type=token, c'è ancora un Implicit flow da sostituire. Se compare grant_type=password, il client sta gestendo direttamente le credenziali dell'utente. Se Authorization Code non usa PKCE, va verificato il supporto del provider e pianificata l'adozione.

Vanno poi controllate le redirect URI registrate, la modalità di rotazione o binding dei refresh token e il modo in cui gli access token vengono trasmessi alle API.

Il passaggio può essere incrementale. Un sistema può continuare a dichiararsi OAuth 2.0 e adottare RFC 9700 oggi. In molti casi è una descrizione più corretta che dichiarare prematuramente compatibilità OAuth 2.1, visto che il documento resta un Internet-Draft e può ancora cambiare prima della pubblicazione finale.

Fonti