Flusso Authorization Code + PKCE
Il flusso Authorization Code + PKCE è il pattern OAuth 2.0 consigliato per tutte le applicazioni che autenticano utenti reali. Questa pagina spiega cos’è PKCE, perché è stato introdotto e come funziona il flusso completo dall’inizio alla fine — incluse le proprietà di sicurezza a ogni passaggio.
Perché Esiste PKCE
Il flusso Authorization Code OAuth 2.0 originale (senza PKCE) ha una vulnerabilità di sicurezza nei client pubblici: l’intercettazione del codice.
Quando Auris reindirizza alla tua applicazione con un authorization code, quel codice viaggia attraverso la barra URL del browser. Su dispositivi mobili, un’applicazione dannosa registrata per gestire lo stesso schema URI personalizzato potrebbe intercettare il redirect.
Se un attaccante intercetta il codice, può scambiarlo per token all’endpoint token. Nel flusso classico, nulla lo impedisce.
PKCE (Proof Key for Code Exchange, RFC 7636) risolve questo problema legando l’authorization code alla specifica sessione client che lo ha richiesto. Solo il client che ha originariamente generato il code verifier può scambiare il codice — anche se un attaccante ha il codice stesso.
Auris applica PKCE a tutti i flussi authorization code. Il metodo di challenge plain viene rifiutato — viene accettato solo il metodo S256 (SHA-256). Non c’è modo di aggirare PKCE in Auris.
Il Meccanismo PKCE
PKCE aggiunge due valori al flusso standard:
Code Verifier: Una stringa casuale crittografica, lunga 43-128 caratteri, usando solo caratteri URL non riservati (A-Z, a-z, 0-9, -, ., _, ~). Questo valore viene mantenuto segreto dal client.
Code Challenge: Una versione trasformata del code verifier, calcolata come:
code_challenge = BASE64URL(SHA256(ASCII(code_verifier)))Il client invia il code challenge (l’hash) all’endpoint di autorizzazione. Quando scambia il codice, il client invia il code verifier grezzo. Auris ricalcola il challenge e conferma che corrisponda. Poiché un attaccante non può invertire un hash SHA-256, non può falsificare il verifier.
Flusso Passo-Passo
Passo 1: Genera il Code Verifier
Il client genera un code_verifier casuale crittograficamente. Deve essere di 43-128 caratteri dall’alfabeto [A-Za-z0-9-._~].
function generateCodeVerifier(): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'
const array = new Uint8Array(64)
crypto.getRandomValues(array)
return Array.from(array)
.map(b => chars[b % chars.length])
.join('')
}
const codeVerifier = generateCodeVerifier()
// Esempio: "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"Archivia il code_verifier in sessionStorage (non localStorage) — deve solo sopravvivere al round-trip del redirect.
Passo 2: Deriva il Code Challenge
Calcola SHA-256(code_verifier) e codifica in Base64URL il risultato:
async function generateCodeChallenge(verifier: string): Promise<string> {
const encoder = new TextEncoder()
const data = encoder.encode(verifier)
const digest = await crypto.subtle.digest('SHA-256', data)
return btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '')
}
const codeChallenge = await generateCodeChallenge(codeVerifier)
// Esempio: "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"Passo 3: Genera lo State
Genera un parametro state casuale per la protezione CSRF.
function generateState(): string {
const array = new Uint8Array(16)
crypto.getRandomValues(array)
return btoa(String.fromCharCode(...array))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '')
}
const state = generateState()
sessionStorage.setItem('pkce_state', state)
sessionStorage.setItem('pkce_code_verifier', codeVerifier)Passo 4: Reindirizza all’Endpoint Authorize
Costruisci l’URL di autorizzazione e reindirizza il browser:
const params = new URLSearchParams({
response_type: 'code',
client_id: 'il-tuo-client-id',
redirect_uri: 'https://app.tuodominio.com/callback',
state: state,
code_challenge: codeChallenge,
code_challenge_method: 'S256',
scope: 'openid profile email',
})
window.location.href = `https://api.altovar.net/api/oauth/authorize?${params}`Passo 5: L’Utente Si Autentica su Auris
Sulla pagina di login hosted di Auris, l’utente:
- Inserisce email e password (o usa login social, magic link, ecc.)
- Completa l’MFA se richiesto dalla policy del tenant o dal risk scoring adattivo
- Vede una schermata di consenso per scope sensibili (solo la prima volta)
Il codice della tua applicazione non è in esecuzione durante questo passaggio.
Passo 6: Auris Reindirizza con il Codice
In caso di autenticazione riuscita, Auris emette un authorization code a breve durata (5 minuti) e reindirizza il browser al tuo redirect_uri:
https://app.tuodominio.com/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz789abcL’authorization code è monouso. Qualsiasi tentativo di usarlo due volte viene rifiutato.
Passo 7: Valida lo State (Protezione CSRF)
Prima di fare qualsiasi cosa con il codice, confronta lo state restituito nella query string con quello archiviato in sessionStorage:
const returnedState = new URLSearchParams(window.location.search).get('state')
const storedState = sessionStorage.getItem('pkce_state')
if (!returnedState || returnedState !== storedState) {
throw new Error('State non corrispondente — possibile attacco CSRF')
}Passo 8: Scambia il Codice per i Token
Recupera il code_verifier archiviato e invialo insieme all’authorization code all’endpoint token:
const code = new URLSearchParams(window.location.search).get('code')
const codeVerifier = sessionStorage.getItem('pkce_code_verifier')
const response = await fetch('https://api.altovar.net/api/auth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'authorization_code',
code: code,
code_verifier: codeVerifier,
redirect_uri: 'https://app.tuodominio.com/callback',
client_id: 'il-tuo-client-id',
}),
})
const data = await response.json()Auris verifica: SHA256(code_verifier) === stored_code_challenge. Se corrispondono, vengono emessi i token.
Passo 9: Ricevi i Token
{
"ok": true,
"data": {
"accessToken": "eyJhbGciOiJSUzI1NiJ9...",
"refreshToken": "rt_...",
"idToken": "eyJhbGciOiJSUzI1NiJ9...",
"expiresIn": 900,
"tokenType": "Bearer"
}
}Pulisci i valori PKCE da sessionStorage:
sessionStorage.removeItem('pkce_state')
sessionStorage.removeItem('pkce_code_verifier')Proprietà di Sicurezza
Proprietà 1: Resistenza all’Intercettazione del Codice
Se un attaccante intercetta l’authorization code, non può comunque scambiarlo per token. Per scambiare il codice, ha bisogno del code_verifier. Il code_verifier non viene mai inviato ad Auris fino al passo 8 — e a quel punto va direttamente tramite HTTPS all’endpoint token, non attraverso la barra URL del browser.
Proprietà 2: Protezione CSRF tramite State
Il parametro state è un valore casuale generato dal client e restituito invariato da Auris. Se un attaccante crea un redirect dannoso con un codice falsificato, la tua applicazione rileverà che lo state non corrisponde.
Proprietà 3: Authorization Code Monouso
Ogni authorization code può essere usato solo una volta. Se Auris rileva un tentativo di replay del codice, rifiuta la seconda richiesta.
Proprietà 4: Binding del Redirect URI
Il redirect_uri usato al momento dello scambio deve corrispondere esattamente a quello registrato nella Console Auris per quell’applicazione.
Proprietà 5: Breve Durata del Codice
Gli authorization code scadono dopo 5 minuti.
Usare l’SDK Auris
Se stai usando un SDK Auris, tutto quanto sopra viene gestito automaticamente:
import { AurisClient } from '@auris/js'
const auris = new AurisClient({
domain: 'api.altovar.net',
clientId: 'il-tuo-client-id',
redirectUri: 'https://app.tuodominio.com/callback',
autoRefresh: true,
})
// Al click del pulsante di login:
await auris.loginWithRedirect()
// Nella tua pagina callback:
const result = await auris.handleRedirectCallback()
console.log(result.user) // L'utente autenticatoConcetti Correlati
- OAuth 2.0 & OIDC — Gli standard di protocollo sottostanti
- Hosted Login (Universal Login) — Come Auris usa PKCE nelle pagine di login hosted
- I Token Spiegati — Quali token vengono emessi dopo lo scambio PKCE
- Guida Hosted Login — Integra il login PKCE nella tua applicazione