Documentação

Verificação de identidade

Reconheça uma pessoa autenticada e restaure o histórico de conversas entre dispositivos, usando uma assinatura que o seu backend controla.

Por que verificar#

Por padrão, o SDK é anônimo: gera um visitor_id estável e o salva no keystore da plataforma. Isso basta para uma conversa em um dispositivo. Para reconhecer um usuário específico, restaurar o histórico quando ele se autentica de novo ou em outro dispositivo, e associar de forma confiável uma conversa a um perfil de contato, o backend precisa de prova de que o cliente é quem afirma ser. Se o SDK simplesmente enviasse “sou o usuário 42”, qualquer pessoa poderia forjar outro id e ler o chat de outra pessoa — por isso o Respondo exige uma assinatura criptográfica, userHash, que só o seu backend consegue produzir.

Obter o identity secret#

O identity_secret é uma string secreta associada ao seu agente (o worker de IA ao qual o canal do seu widget está conectado). Gere-o no dashboard, em Channels → Widget → Identity verification. Como vive no agente, é compartilhado por todos os canais atendidos por esse agente — tanto o widget web quanto o SDK móvel. Concede o direito de assinar identidades, por isso deve viver apenas no seu backend e nunca deve ser enviado no app.

A fórmula do userHash#

O userHash é um HMAC-SHA256 sobre uma única string de identidade assinada, codificada em hexadecimal minúsculo:

Fórmulatext
userHash = HMAC_SHA256( identity_secret, payload )

payload = userId          // se userId estiver definido
        = email           // caso contrário, se email estiver definido
        = (invalid)       // se ambos estiverem vazios, não há nada para assinar
  • O segredo é a chave do HMAC; a string de identidade é a mensagem — e não o contrário.
  • Assine exatamente uma string — o userId em bruto (ou o e-mail), sem salt nem envelope JSON.
  • Se você passar tanto userId quanto e-mail, assine o userId (tem prioridade).
  • A saída é hexadecimal (64 caracteres para SHA-256), não base64.

Exemplos de backend#

Calcule a assinatura no seu backend e entregue o userHash pronto ao app.

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

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

// Retorna o userHash que deve ser passado ao Respondo.identify no cliente móvel.
function computeUserHash(identitySecret, userId) {
  return crypto
    .createHmac("sha256", identitySecret)
    .update(userId, "utf8")
    .digest("hex");
}
Pythonpython
import hmac
import hashlib

# Retorna o userHash que deve ser passado ao Respondo.identify no cliente móvel.
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
// Retorna o userHash que deve ser passado ao Respondo.identify no cliente móvel.
function computeUserHash(string $identitySecret, string $userId): string {
    return hash_hmac('sha256', $userId, $identitySecret);
}

Como o hash chega ao Respondo#

O Respondo não expõe nenhum endpoint de identidade. Não há nenhuma rota /identity para chamar nem nada para registrar. O userHash é um campo que viaja nas requisições que o SDK já faz.

São dois saltos, e só o primeiro é da sua responsabilidade:

  1. O seu backend → o seu app. Entrega o hash como preferir. A opção mais barata é um campo adicional na resposta de login/inicialização que o app já recebe — sem requisição extra. Um endpoint dedicado no seu próprio backend (por exemplo POST /myapp/identity que retorna { userId, userHash }) funciona igualmente bem. O Respondo não hospeda esse endpoint — é você que o implementa.
  2. O seu app → o Respondo. Isso o SDK faz por você. Assim que você chamar identify, o SDK anexa o hash a todas as requisições relevantes e o backend o verifica de novo a cada vez.
Onde o SDK o coloca (referência — não envie isso à mão)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 (frames JSON de subscribe/identify após conectar — não na URL do handshake)
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

O hash é reverificado em cada requisição, não trocado uma única vez por uma sessão — é isso que torna um userId roubado inútil por si só.

Se o endpoint de entrega no seu backend ainda não estiver feito, a requisição do próprio app retorna 404, o identify nunca é chamado e o chat roda de forma anônima. Isso é comportamento esperado, não um erro do Respondo — um 404 no seu próprio caminho é uma tarefa do seu lado, não uma integração quebrada.

Passar a identidade ao SDK#

Obtenha a identidade assinada do seu backend e depois passe o userHash ao identify em qualquer 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,
));

Comportamento com userHash inválido#

Quando a verificação está ativada no agente e a assinatura está ausente ou errada, o backend faz uma degradação silenciosa para anônimo: o chat continua funcionando, o visitor_id é mantido, e a conversa é associada ao contato anônimo — mas não há vínculo com o perfil nem histórico entre dispositivos. Se um usuário “não é reconhecido”, é quase sempre a assinatura: verifique que assinou o userId (não o e-mail nem JSON), que usou o identity_secret certo, e que emitiu hexadecimal minúsculo. Se o identity_secret do agente estiver vazio, a verificação está desligada e userId / e-mail são aceites tal como estão.

Rodar o identity_secret é, na prática, uma migração abrupta: todos os hashes produzidos com o segredo antigo deixam de verificar de imediato, por isso os usuários já autenticados voltam silenciosamente a anônimo até o seu backend recalcular e voltar a fornecer o userHash com o novo segredo. Rode o segredo apenas quando puder atualizar o lado da assinatura na mesma janela.