Документация

Проверка личности

Узнавайте вошедшего человека и восстанавливайте историю его диалогов на разных устройствах, используя подпись, которой управляет ваш backend.

Зачем проверять#

По умолчанию SDK анонимен: он генерирует стабильный visitor_id и держит его в платформенном keystore. Этого достаточно для одного диалога на одном устройстве. Чтобы узнать конкретного пользователя, восстановить историю при повторном входе или на другом устройстве и надёжно привязать диалог к профилю контакта, backend нужно доказательство, что клиент — тот, за кого себя выдаёт. Если бы SDK просто отправлял «я пользователь 42», любой мог бы подделать чужой id и прочитать чужой чат — поэтому Respondo требует криптографическую подпись, userHash, которую может создать только ваш backend.

Получение identity secret#

identity_secret — это секретная строка, привязанная к вашему агенту (ИИ-работнику, к которому подключён канал вашего виджета). Сгенерируйте его в панели управления: Каналы → Виджет → Проверка личности. Секрет лежит на агенте, поэтому он общий для всех каналов этого агента — и веб-виджета, и мобильного SDK. Он даёт право подписывать личности, поэтому должен жить только на вашем backend и никогда не поставляться в приложении.

Формула userHash#

userHash — это HMAC-SHA256 над единственной подписываемой строкой личности, закодированный как hex в нижнем регистре:

Формулаtext
userHash = HMAC_SHA256( identity_secret, payload )

payload = userId          // если userId задан
        = email           // иначе, если задан email
        = (invalid)       // если оба пусты, подписывать нечего
  • Секрет — это ключ HMAC; строка личности — это сообщение, а не наоборот.
  • Подписывайте ровно одну строку — сырой userId (или email), без соли и JSON-обёртки.
  • Если вы передаёте и userId, и email, подписывайте userId(у него приоритет).
  • Вывод — hex (64 символа для SHA-256), не base64.

Примеры для backend#

Вычислите подпись на своём backend и передайте готовый userHash в приложение.

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

// HMAC_SHA256(identity_secret, userId) как hex в нижнем регистре.
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");

// Возвращает userHash для передачи в Respondo.identify на мобильном клиенте.
function computeUserHash(identitySecret, userId) {
  return crypto
    .createHmac("sha256", identitySecret)
    .update(userId, "utf8")
    .digest("hex");
}
Pythonpython
import hmac
import hashlib

# Возвращает userHash для передачи в Respondo.identify на мобильном клиенте.
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
// Возвращает userHash для передачи в Respondo.identify на мобильном клиенте.
function computeUserHash(string $identitySecret, string $userId): string {
    return hash_hmac('sha256', $userId, $identitySecret);
}

Как хэш попадает в Respondo#

У Respondo нет отдельного identity-эндпоинта. Дёргать нечего: ручки /identity не существует и регистрировать ничего не нужно. userHash — это поле, которое едет в запросах, что SDK и так делает.

Два хопа, и строите вы только первый:

  1. Ваш backend → ваше приложение. Доставляете хэш как удобно. Дешевле всего — дополнительным полем в ответе логина/бутстрапа, который вы и так отдаёте (лишнего запроса нет). Отдельная ручка на вашем собственном backend (например POST /myapp/identity { userId, userHash }) работает не хуже. Respondo эту ручку не предоставляет — её пишете вы.
  2. Ваше приложение → Respondo. Делает SDK. После вызова identify хэш сам прикладывается к нужным запросам, а backend перепроверяет подпись на каждом.
Куда SDK кладёт хэш (справочно — руками слать не нужно)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 (JSON-фреймы subscribe/identify после подключения — не в 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

Подпись перепроверяется на каждом запросе, а не обменивается один раз на сессию — именно поэтому украденный userId сам по себе бесполезен.

Если ручка доставки на вашем backend ещё не написана, запрос вашего же приложения вернёт 404, identify не вызовется, и чат поедет анонимно. Это ожидаемое поведение, а не ошибка Respondo: 404 на вашем собственном пути — задача на вашей стороне, а не сломанная интеграция.

Передача личности в SDK#

Получите подписанную личность со своего backend, затем передайте userHash в identify на любой платформе:

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

Поведение при неверном userHash#

Когда проверка включена у агента, а подпись отсутствует или неверна, backend выполняет тихое понижение до анонима: чат по-прежнему работает, visitor_id сохраняется, а диалог привязывается к анонимному контакту — но без связи с профилем и без кросс-девайс-истории. Если пользователь «не узнаётся», почти всегда дело в подписи: проверьте, что вы подписали userId (не email и не JSON), использовали правильный identity_secret и выдали hex в нижнем регистре. Если identity_secret агента пуст, проверка выключена, и userId / email принимаются как есть.

Ротация identity_secret — это, по сути, жёсткое переключение: каждый хеш, созданный со старым секретом, тут же перестаёт проходить проверку, поэтому уже вошедшие пользователи молча откатываются до анонима, пока ваш backend не пересчитает и не переподаст их userHash с новым секретом. Меняйте секрет только тогда, когда можете обновить подписывающую сторону в том же окне.