Skip to Content

CIBA (Client Initiated Backchannel Authentication)

La plupart des flux d’authentification supposent que l’utilisateur initie l’authentification. Il ouvre une application, clique sur “Se connecter”, et s’authentifie lui-même.

CIBA (Client Initiated Backchannel Authentication) est conçu pour les scénarios où l’authentification est initiée par quelqu’un ou quelque chose autre que la personne qui s’authentifie :

  • Centre d’appels : Un agent téléphonique déclenche l’authentification de l’appelant
  • Terminal de paiement : Le terminal initie l’autorisation de paiement sur le téléphone du client
  • Enceinte intelligente : “Alexa, transfère 200 euros” → challenge d’authentification envoyé au téléphone
  • Kiosque : Le kiosque initie le check-in avec authentification sur le téléphone du client
  • Autorisation de virement bancaire : La banque envoie une notification push pour confirmer une transaction

CIBA vs Device Flow

Bien que les deux impliquent un appareil secondaire, ils sont fondamentalement différents :

Device FlowCIBA
Initié parL’appareil (l’utilisateur voit un code)Le serveur/agent (l’utilisateur reçoit une notification)
Interface utilisateurEntre un code sur un appareil secondaireApprouve/refuse une notification push
Exige que l’utilisateurVisite une URL et entre un codeAit l’app mobile Auris ou une app avec notification push
Cas d’usage typiqueCLI, Smart TVCall center, POS, IoT

Le Flux CIBA

┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Agent Call │ │ Serveur Auris │ │ Téléphone │ │ Center │ │ │ │ Utilisateur │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ │ │ │ 1. POST /ciba │ │ │ login_hint: alice@... │ │ │ binding_message: │ │ │ "Appel client #1234" │ │ │─────────────────────>│ │ │ │ │ │ 2. auth_req_id │ │ │<─────────────────────│ │ │ │ │ │ │ 3. Push notification │ │ │ "Agent demande accès │ │ │ pour Appel #1234" │ │ │─────────────────────>│ │ │ │ │ 4. Poll token │ 4. Utilisateur │ │ endpoint │ approuve/refuse │ │─────────────────────>│<─────────────────────│ │ │ │ │ 5. access_token │ │ │<─────────────────────│ │

Étape 1 : Initier l’Authentification Backchannel

POST /api/oauth/ciba Content-Type: application/x-www-form-urlencoded Authorization: Basic BASE64(client_id:client_secret) [email protected] &scope=openid+profile+phone &binding_message=Appel+client+%231234+-+Agent+Bob &requested_expiry=300 &client_notification_token=NOTIFICATION_TOKEN

Paramètres :

ParamètreDescription
login_hintIdentifie l’utilisateur à authentifier (email, user ID, ou téléphone)
scopeScopes OAuth demandés
binding_messageTexte court affiché à l’utilisateur pour lier la requête à sa session
requested_expirySecondes avant expiration de la requête auth (max 600)
client_notification_tokenToken opaque pour la notification côté client (mode Ping/Push)

Étape 2 : Réponse Initiale

{ "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac9", "expires_in": 300, "interval": 5 }

Étape 3 : Notification Push à l’Utilisateur

Auris envoie une notification push à l’appareil mobile de l’utilisateur via son app Auris (ou ton app si tu as intégré le SDK). La notification affiche le binding_message.

Message de liaison et sécurité. Le binding_message est crucial pour prévenir les attaques de “confused deputy” — où un utilisateur est trompé en approuvant une requête pour une session différente de celle qu’il croit autoriser. Rends-le spécifique : “Agent Bob, Appel Client #1234, 15:23” est mieux que “Demande de connexion”.

Ne jamais inclure des données sensibles (mots de passe, numéros de carte) dans le binding_message — il est visible sur l’écran de verrouillage.

Étape 4 : Polling (Mode Poll)

En mode Poll, le client poll le token endpoint pendant que l’utilisateur est en cours d’authentification :

POST /api/auth/token Content-Type: application/x-www-form-urlencoded Authorization: Basic BASE64(client_id:client_secret) grant_type=urn:openid:params:grant-type:ciba &auth_req_id=1c266114-a1be-4252-8ad1-04986c5b9ac9

Réponses possibles :

RéponseAction
authorization_pendingContinuer le polling
slow_downAugmenter l’intervalle de 5 secondes
access_deniedL’utilisateur a refusé — arrêter
expired_tokenRequête expirée — informer l’agent
200 OK avec tokensSuccès

Les Trois Modes de Notification

Mode Poll (Défaut)

Le plus simple. Le client poll le token endpoint jusqu’à ce que l’utilisateur approuve ou refuse. Pas de callback côté serveur nécessaire.

Avantage : Simple à implémenter. Inconvénient : Polling de la bande passante, latence légèrement plus haute.

Mode Ping

Le serveur Auris envoie une notification HTTP POST à l’URL de callback du client quand l’utilisateur s’authentifie. Le client récupère ensuite les tokens.

Auris → POST https://callcenter.example.com/ciba/callback Body: {"auth_req_id": "1c266114-..."}

Le client fait alors exactement un appel au token endpoint (pas de polling).

Avantage : Plus efficace que le polling, toujours simple. Inconvénient : Nécessite une URL de callback accessible depuis internet.

Mode Push

Auris envoie les tokens directement dans la requête de callback — le client n’a même pas besoin d’appeler le token endpoint.

Avantage : Latence minimale, moins d’appels API. Inconvénient : Les tokens transitent vers le callback — l’URL doit être HTTPS sécurisée.

Exemple TypeScript — Call Center

async function authenticateCallerForAgent( callerEmail: string, agentId: string, callId: string ): Promise<{ accessToken: string; callerProfile: UserProfile }> { // Étape 1 : Initier l'authentification const cibaRes = await fetch('https://auth.yourdomain.com/api/oauth/ciba', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', Authorization: `Basic ${btoa(`${CLIENT_ID}:${CLIENT_SECRET}`)}`, }, body: new URLSearchParams({ login_hint: callerEmail, scope: 'openid profile phone', binding_message: `Agent ${agentId} | Appel ${callId} | ${new Date().toLocaleTimeString()}`, requested_expiry: '120', }), }) const { auth_req_id, interval } = await cibaRes.json() // Notifier l'agent : "Authentification en cours..." console.log(`Demande d'authentification envoyée à ${callerEmail}`) // Étape 2 : Polling avec backoff let pollIntervalMs = interval * 1000 while (true) { await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)) const tokenRes = await fetch('https://auth.yourdomain.com/api/auth/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', Authorization: `Basic ${btoa(`${CLIENT_ID}:${CLIENT_SECRET}`)}`, }, body: new URLSearchParams({ grant_type: 'urn:openid:params:grant-type:ciba', auth_req_id, }), }) const data = await tokenRes.json() if (tokenRes.ok) { return { accessToken: data.access_token, callerProfile: parseIdToken(data.id_token), } } if (data.error === 'slow_down') { pollIntervalMs += 5000 } else if (data.error === 'access_denied') { throw new Error('L\'appelant a refusé l\'authentification') } else if (data.error === 'expired_token') { throw new Error('Authentification expirée') } // authorization_pending → continuer } }

Concepts Associés

  • Device Flow — Quand l’utilisateur initie lui-même (Smart TV, CLI)
  • OAuth 2.0 & OIDC — Le cadre d’autorisation sous-jacent
  • Tokens — Access tokens, refresh tokens et leurs propriétés
  • DPoP — Lier les tokens à une clé cryptographique pour plus de sécurité