Documentación

Verificación de identidad

Reconoce a una persona autenticada y restaura su historial de conversaciones en todos sus dispositivos, usando una firma que tu backend controla.

Por qué verificar#

Por defecto, el SDK es anónimo: genera un visitor_id estable y lo conserva en el almacén de claves (keystore) de la plataforma. Eso basta para una conversación en un dispositivo. Para reconocer a un usuario concreto, restaurar el historial al volver a iniciar sesión o en otro dispositivo, y vincular de forma fiable una conversación con un perfil de contacto, el backend necesita una prueba de que el cliente es quien dice ser. Si el SDK simplemente enviara «soy el usuario 42», cualquiera podría suplantar otro id y leer el chat de otra persona, así que Respondo requiere una firma criptográfica, userHash, que solo tu backend puede producir.

Obtener el identity secret#

El identity_secret es una cadena secreta vinculada a tu agente (el trabajador de IA al que está conectado el canal de tu widget). Genéralo en el panel de control en Canales → Widget → Verificación de identidad. Como reside en el agente, todos los canales asociados a ese agente —tanto el widget web como el SDK móvil— comparten el mismo secreto. Otorga el derecho a firmar identidades, por lo que debe residir únicamente en tu backend y nunca debe incluirse en la aplicación.

La fórmula del userHash#

userHash es un HMAC-SHA256 sobre una única cadena de identidad firmada, codificado como hexadecimal en minúsculas:

Fórmulatext
userHash = HMAC_SHA256( identity_secret, payload )

payload = userId          // si userId está definido
        = email           // en caso contrario, si email está definido
        = (invalid)       // si ambos están vacíos, no hay nada que firmar
  • El secreto es la clave HMAC; la cadena de identidad es el mensaje, no al revés.
  • Firma exactamente una cadena: el userId (o el email) en crudo, sin sal (salt) ni envoltorio JSON.
  • Si pasas tanto userId como el email, firma el userId (tiene prioridad).
  • La salida es hexadecimal (64 caracteres para SHA-256), no base64.

Ejemplos de backend#

Calcula la firma en tu backend y entrega el userHash finalizado a la aplicación.

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

// HMAC_SHA256(identity_secret, userId) como hexadecimal en minúsculas.
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");

// Devuelve el userHash para pasarlo a Respondo.identify en el cliente móvil.
function computeUserHash(identitySecret, userId) {
  return crypto
    .createHmac("sha256", identitySecret)
    .update(userId, "utf8")
    .digest("hex");
}
Pythonpython
import hmac
import hashlib

# Devuelve el userHash para pasarlo a Respondo.identify en el cliente móvil.
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
// Devuelve el userHash para pasarlo a Respondo.identify en el cliente móvil.
function computeUserHash(string $identitySecret, string $userId): string {
    return hash_hmac('sha256', $userId, $identitySecret);
}

Cómo llega el hash a Respondo#

Respondo no expone ningún endpoint de identidad. No hay ninguna ruta /identity que llamar ni nada que registrar. El userHash es un campo que viaja en las peticiones que el SDK ya realiza.

Dos saltos, y solo el primero te toca construirlo a ti:

  1. Tu backend → tu aplicación. Entregas el hash como prefieras. La opción más barata es un campo adicional en la respuesta de login/bootstrap que ya devuelves, sin ninguna petición extra. Un endpoint dedicado en tu propio backend (por ejemplo POST /myapp/identity que devuelva { userId, userHash }) funciona igual de bien. Respondo no aloja ese endpoint: lo implementas tú.
  2. Tu aplicación → Respondo. Ya está resuelto. En cuanto llamas a identify, el SDK adjunta el hash a cada petición relevante y el backend lo vuelve a verificar cada vez.
Dónde lo coloca el SDK (a modo de referencia: no envías esto 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

El hash se vuelve a comprobar en cada petición, no se canjea una sola vez por una sesión: eso es lo que hace que un userId robado sea inútil por sí solo.

Si el endpoint de entrega en tu backend aún no está construido, la propia petición de tu aplicación devuelve 404, identify nunca se llama y el chat funciona de forma anónima. Ese es el comportamiento esperado, no un error de Respondo: un 404 en tu propia ruta es una tarea pendiente de tu lado, no una integración rota.

Pasar la identidad al SDK#

Obtén la identidad firmada de tu backend y luego pasa el userHash a identify en cualquier plataforma:

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,
));

Comportamiento con un userHash inválido#

Cuando la verificación está habilitada en el agente y la firma falta o es incorrecta, el backend realiza una degradación silenciosa a anónimo: el chat sigue funcionando, se conserva el visitor_id y la conversación se vincula al contacto anónimo, pero no hay ningún enlace con el perfil ni historial entre dispositivos. Si un usuario «no es reconocido», casi siempre es la firma: comprueba que firmaste el userId (no el email ni JSON), que usaste el identity_secret correcto y que emitiste hexadecimal en minúsculas. Si el identity_secret del agente está vacío, la verificación está desactivada y el userId / email se aceptan tal cual.

Rotar el identity_secret es, en la práctica, un corte definitivo: todos los hashes producidos con el secreto antiguo dejan de verificarse de inmediato, así que los usuarios ya autenticados vuelven silenciosamente a ser anónimos hasta que tu backend recalcule y vuelva a proporcionar su userHash con el nuevo secreto. Cambia el secreto solo cuando puedas actualizar el lado de la firma en la misma ventana.