Documentazione

Verifica dell’identità

Riconosci una persona autenticata e ripristina la cronologia delle sue conversazioni su più dispositivi, usando una firma controllata dal tuo backend.

Perché verificare#

Per impostazione predefinita l’SDK è anonimo: genera un visitor_id stabile e lo conserva nel keystore della piattaforma. È sufficiente per una conversazione su un dispositivo. Per riconoscere un utente specifico, ripristinare la cronologia al nuovo accesso o su un altro dispositivo, e legare in modo affidabile una conversazione a un profilo di contatto, il backend ha bisogno della prova che il client sia chi dichiara di essere. Se l’SDK inviasse semplicemente «sono l’utente 42», chiunque potrebbe falsificare un altro id e leggere la chat di qualcun altro — perciò Respondo richiede una firma crittografica, userHash, che solo il tuo backend può produrre.

Ottenere l’identity secret#

L’identity_secret è una stringa segreta legata al tuo agente (il worker IA a cui è connesso il canale del tuo widget). Generalo nella dashboard in Channels → Widget → Identity verification. Poiché risiede sull’agente, è condiviso da ogni canale collegato a quell’agente — sia il widget web sia l’SDK mobile. Concede il diritto di firmare le identità, quindi deve risiedere solo sul tuo backend e non va mai incluso nell’app.

La formula di userHash#

userHash è un HMAC-SHA256 su un’unica stringa di identità firmata, codificato in esadecimale minuscolo:

Formulatext
userHash = HMAC_SHA256( identity_secret, payload )

payload = userId          // se userId è impostato
        = email           // altrimenti, se email è impostata
        = (non valido)    // se entrambi sono vuoti, non c'è nulla da firmare
  • Il secret è la chiave HMAC; la stringa di identità è il messaggio — non il contrario.
  • Firma esattamente una stringa — il userId grezzo (o l’email), senza salt né wrapper JSON.
  • Se passi sia userId sia email, firma lo userId (ha la priorità).
  • L’output è esadecimale (64 caratteri per SHA-256), non base64.

Esempi per il backend#

Calcola la firma sul tuo backend e passa lo userHash già pronto all’app.

Gogo
import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
)

// HMAC_SHA256(identity_secret, userId) come esadecimale minuscolo.
func ComputeUserHash(identitySecret, userID string) string {
    mac := hmac.New(sha256.New, []byte(identitySecret))
    mac.Write([]byte(userID))
    return hex.EncodeToString(mac.Sum(nil))
}
Node.jsjavascript
const crypto = require("crypto");

// Restituisce lo userHash da passare a Respondo.identify sul client mobile.
function computeUserHash(identitySecret, userId) {
  return crypto
    .createHmac("sha256", identitySecret)
    .update(userId, "utf8")
    .digest("hex");
}
Pythonpython
import hmac
import hashlib

# Restituisce lo userHash da passare a Respondo.identify sul client mobile.
def compute_user_hash(identity_secret: str, user_id: str) -> str:
    return hmac.new(
        identity_secret.encode(),
        user_id.encode(),
        hashlib.sha256,
    ).hexdigest()
PHPphp
<?php
// Restituisce lo userHash da passare a Respondo.identify sul client mobile.
function computeUserHash(string $identitySecret, string $userId): string {
    return hash_hmac('sha256', $userId, $identitySecret);
}

Come l’hash arriva a Respondo#

Respondo non espone alcun endpoint di identità. Non c’è nessuna rotta /identity da chiamare e non c’è nulla da registrare. Lo userHash è un campo che viaggia sulle richieste che l’SDK già effettua.

Due passaggi, e solo il primo devi costruirlo tu:

  1. Il tuo backend → la tua app. Consegni l’hash come preferisci. L’opzione più economica è un campo aggiuntivo nella risposta di login/bootstrap che già restituisci — nessun round trip in più. Un endpoint dedicato sul tuo backend (ad esempio POST /myapp/identity che restituisce { userId, userHash }) funziona altrettanto bene. Respondo non ospita quell’endpoint — lo implementi tu.
  2. La tua app → Respondo. Se ne occupa l’SDK. Una volta chiamato identify, l’SDK allega l’hash a ogni richiesta pertinente e il backend lo riverifica ogni volta.
Dove l’SDK lo inserisce (per riferimento — non devi inviarli a mano)text
POST /api/v1/chat                      body   identity.userHash
GET  /api/v1/chat/resume               query  user_hash
GET  /api/v1/chat/history              query  user_hash
GET  /api/v1/chat/ws                   frames    user_hash (subscribe/identify JSON frames after connect — not in the handshake URL)
GET  /api/v1/widget/tours              query  user_hash
GET  /api/v1/widget/checklists         query  user_hash
POST /api/v1/widget/push/register      body   user_hash

L’hash viene riverificato a ogni richiesta, non scambiato una volta sola per una sessione — è questo che rende inutile di per sé un userId rubato.

Se l’endpoint di consegna sul tuo backend non è ancora stato costruito, la richiesta della tua stessa app restituisce 404, identify non viene mai chiamato e la chat procede in modo anonimo. È un comportamento previsto, non un errore di Respondo: un 404 su un tuo percorso è un to-do dalla tua parte, non un’integrazione rotta.

Passare l’identità all’SDK#

Recupera l’identità firmata dal tuo backend, poi passa lo userHash a identify su qualsiasi piattaforma:

Kotlinkotlin
Respondo.identify(
    RespondoIdentity(userId = "42", email = "user@example.com", userHash = hash),
)
Swiftswift
Respondo.identify(
    RespondoIdentity(userId: "42", email: "user@example.com", userHash: hash)
)
Dartdart
Respondo.identify(RespondoIdentity(
  userId: '42', email: 'user@example.com', userHash: hash,
));

Comportamento con userHash non valido#

Quando la verifica è abilitata sull’agente e la firma manca o è errata, il backend esegue un downgrade silenzioso ad anonimo: la chat continua a funzionare, il visitor_id viene mantenuto e la conversazione è legata al contatto anonimo — ma non c’è alcun collegamento al profilo né cronologia tra dispositivi. Se un utente «non viene riconosciuto», quasi sempre è la firma: verifica di aver firmato lo userId (non l’email né JSON), di aver usato l’ identity_secret giusto e di aver emesso esadecimale minuscolo. Se l’ identity_secret dell’agente è vuoto, la verifica è disattivata e userId / email vengono accettati così come sono.

Ruotare l’ identity_secret è di fatto un cambio netto: ogni hash prodotto con il vecchio secret smette di verificarsi all’istante, quindi gli utenti già autenticati ripiegano silenziosamente su anonimo finché il tuo backend non ricalcola e rifornisce il loro userHash con il nuovo secret. Ruota il secret solo quando puoi aggiornare il lato firma nella stessa finestra.