CIBA (Client Initiated Backchannel Authentication)
Il Problema: Autenticazione Avviata da Qualcun Altro
I flussi OAuth 2.0 tradizionali assumono che un singolo utente interagisca con un singolo dispositivo. Questo modello funziona per le web app e le mobile app, ma cade quando la persona che richiede l’autenticazione non è la stessa che autentica.
| Scenario | Perché OAuth Standard Fallisce |
|---|---|
| Agente call center che verifica un cliente | L’agente non può digitare la password del cliente |
| Terminale di pagamento in un negozio | Il cassiere avvia, il cliente approva sul telefono |
| Smart speaker per acquisti | Nessuno schermo per il login |
| Kiosk check-in sanitario | Il receptionist avvia, il paziente approva sul telefono |
| Autorizzazione bonifico bancario | Il sistema bancario avvia, il titolare approva da remoto |
Cos’è CIBA
CIBA (Client Initiated Backchannel Authentication) è un’estensione OpenID Connect che consente a un’applicazione client di avviare un flusso di autenticazione per un utente noto, dove l’utente autentica su un dispositivo di autenticazione separato (tipicamente il telefono) tramite notifica push, SMS o email.
La distinzione chiave dagli altri flussi OAuth:
- Authorization Code + PKCE: L’utente guida il flusso dall’inizio alla fine sullo stesso dispositivo.
- Device Flow: Il client mostra un codice, l’utente visita un URL e lo inserisce. L’utente avvia l’interazione sul dispositivo secondario.
- CIBA: Il client avvia, il server invia una notifica all’utente. L’utente reagisce solo.
Come Funziona CIBA: Passo per Passo
Passo 1: Il Client Invia una Richiesta di Autenticazione Backchannel
POST /api/oauth/ciba HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer <client_access_token>
[email protected]
&scope=openid profile
&binding_message=Verifica identità per agente Sara (rif: TX-9821)
&requested_expiry=120
&client_notification_token=notification-callback-token-xyz| Parametro | Obbligatorio | Descrizione |
|---|---|---|
login_hint | Sì | Identifica l’utente — email, numero di telefono o user ID |
scope | Sì | Scope OAuth richiesti (deve includere openid) |
binding_message | Consigliato | Descrizione leggibile dall’uomo mostrata all’utente sul dispositivo di autenticazione |
requested_expiry | Opzionale | Durata di validità della richiesta (secondi). Default: 300 |
client_notification_token | Condizionale | Richiesto per le modalità ping e push |
Passo 2: Il Server Restituisce un ID di Richiesta di Autenticazione
{
"auth_req_id": "ciba_req_1a2b3c4d5e6f7g8h",
"expires_in": 120,
"interval": 5
}Passo 3: Il Server Notifica l’Utente
Auris invia una notifica al dispositivo di autenticazione dell’utente tramite uno dei canali configurati:
- Notifica push: Push nativo per mobile
- SMS: Messaggio con un link alla pagina di approvazione
- Email: Email con un link alla pagina di approvazione
La notifica include il binding_message affinché l’utente sappia esattamente cosa sta approvando.
Passo 4: L’Utente Approva o Nega
L’utente vede il binding message e il nome dell’applicazione richiedente sul suo dispositivo di autenticazione. Può approvare o negare.
Passo 5: Il Client Ottiene i Token
Come il client riceve i token dipende dalla modalità di notifica configurata.
Le Tre Modalità di Notifica
Modalità Poll
La modalità più semplice. Il client fa polling al token endpoint all’interval configurato, esattamente come nel Device Flow:
POST /api/auth/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=urn:openid:params:grant-type:ciba
&auth_req_id=ciba_req_1a2b3c4d5e6f7g8h
&client_id=call-center-app
&client_secret=client-secretAdatto per: Integrazioni semplici dove una latenza di 5 secondi è accettabile.
Modalità Ping
Il server invia un HTTP POST all’URL di callback registrato del client quando l’utente risponde. Il callback contiene solo l’auth_req_id — il client deve poi recuperare i token dal token endpoint.
Adatto per: Sistemi di produzione dove il client ha un URL di callback raggiungibile pubblicamente e ha bisogno di latenza inferiore alla modalità poll.
Modalità Push
Il server invia i token direttamente all’URL di callback del client. Il client non chiama mai il token endpoint.
Adatto per: Latenza minima. Tuttavia, i token viaggiano sulla rete verso il callback del client, aumentando la superficie d’attacco.
Confronto Modalità
| Dimensione | Poll | Ping | Push |
|---|---|---|---|
| Latenza | Alta (intervallo polling) | Bassa (avviata dal server) | Minima (token nel callback) |
| Complessità client | Semplice (loop polling) | Media (endpoint callback + fetch token) | Media (endpoint callback) |
| Infrastruttura client | Nessuna (solo outbound) | Richiede URL callback pubblico | Richiede URL callback pubblico |
Auris supporta tutte e tre le modalità. La modalità Poll è predefinita per le nuove applicazioni. Per usare le modalità ping o push, registra un backchannel_client_notification_endpoint nelle impostazioni dell’applicazione.
Il Binding Message
Il binding_message è probabilmente la funzionalità di sicurezza più importante di CIBA. Senza di esso, CIBA è vulnerabile agli attacchi di confused deputy: un attaccante avvia una richiesta CIBA per un utente vittima, e la vittima vede un generico “Approva login?” senza contesto.
Con un binding message, la vittima vede:
“Autorizza bonifico di €5.000 al conto che termina in 7892 (rif: WT-2024-0918)”
Se la vittima non ha avviato un bonifico, sa di dover negare la richiesta.
Il binding_message viene mostrato sul dispositivo dell’utente, che potrebbe essere una notifica push visibile sulla schermata di blocco. Non includere mai password, numeri di carta di credito completi o altre informazioni sensibili nel binding message.
Confronto: CIBA vs Device Flow
| Dimensione | Device Flow | CIBA |
|---|---|---|
| Chi avvia | Utente (visita un URL) | Server (invia notifica) |
| Inserimento codice | L’utente digita il codice manualmente | Nessun inserimento codice; l’utente approva |
| Registrazione utente preventiva | Non richiesta | Richiesta (il server deve sapere come raggiungere l’utente) |
| Utenti anonimi | Supportati | Non supportati |
| Latenza UX | Alta (l’utente deve visitare URL, digitare codice) | Bassa (l’utente tocca approva sulla notifica) |
| Infrastruttura notifica | Nessuna | Richiede capacità push/SMS/email |
Esempio di Codice: Flusso Agente Call Center
async function verifyCustomerIdentity(
customerEmail: string,
agentName: string,
referenceNumber: string
) {
const cibaResponse = await fetch('https://auth.example.com/api/oauth/ciba', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Bearer ${agentAccessToken}`,
},
body: new URLSearchParams({
login_hint: customerEmail,
scope: 'openid profile',
binding_message: `Verifica identità da ${agentName} (rif: ${referenceNumber})`,
requested_expiry: '120',
}),
})
const { auth_req_id, interval, expires_in } = await cibaResponse.json()
console.log(`Verifica inviata a ${customerEmail}. In attesa di approvazione...`)
let pollInterval = interval * 1000
const deadline = Date.now() + expires_in * 1000
while (Date.now() < deadline) {
await new Promise(resolve => setTimeout(resolve, pollInterval))
const tokenResponse = await fetch('https://auth.example.com/api/auth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'urn:openid:params:grant-type:ciba',
auth_req_id,
client_id: 'call-center-app',
client_secret: 'client-secret',
}),
})
if (tokenResponse.ok) {
const { id_token } = await tokenResponse.json()
console.log('Identità cliente verificata.')
return id_token
}
const error = await tokenResponse.json()
if (error.error === 'slow_down') { pollInterval += 5000; continue }
if (error.error === 'authorization_pending') continue
if (error.error === 'access_denied') {
throw new Error('Il cliente ha negato la richiesta di verifica.')
}
throw new Error(`Verifica fallita: ${error.error_description}`)
}
throw new Error('Richiesta di verifica scaduta. Il cliente non ha risposto in tempo.')
}Concetti Correlati
- Device Authorization Flow — Un altro flusso di autenticazione disaccoppiato, avviato dall’utente
- OAuth 2.0 & OIDC — Il framework di autorizzazione che CIBA estende
- Token Spiegati — Struttura JWT, ID token e token di accesso
- DPoP (Proof of Possession) — Token sender-constrained, combinabili con CIBA