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

Верифікація особи

Упізнавайте залогінену людину й відновлюйте історію її розмов на різних пристроях, використовуючи підпис, який контролює ваш бекенд.

Навіщо верифікувати#

За замовчуванням SDK анонімний: він генерує стабільний visitor_id і тримає його в платформенному сховищі ключів (keystore). Цього достатньо для однієї розмови на одному пристрої. Щоб упізнати конкретного користувача, відновити історію при повторному вході чи на іншому пристрої й надійно прив’язати розмову до профілю контакту, бекенду потрібен доказ, що клієнт — це той, за кого себе видає. Якби SDK просто надсилав «я користувач 42», будь-хто міг би підмінити чужий ідентифікатор і читати чужий чат — тож Respondo вимагає криптографічний підпис, userHash, який може створити лише ваш бекенд.

Отримання секрету особи#

identity_secret — це секретний рядок, прив’язаний до вашого агента (AI-працівника, до якого підключений канал вашого віджета). Згенеруйте його в дашборді: Channels → Widget → Identity verification. Секрет лежить на агенті, тож він спільний для всіх каналів цього агента — і для вебвіджета, і для мобільного SDK. Він дає право підписувати особи, тож має жити лише на вашому бекенді й ніколи не постачатися в застосунку.

Формула 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.

Приклади для бекенду#

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

Якщо ендпоінт доставки на вашому бекенді ще не написаний, запит вашого ж застосунку поверне 404, identify не викличеться, і чат працюватиме анонімно. Це очікувана поведінка, а не помилка Respondo: 404 на вашому власному шляху — задача на вашому боці, а не зламана інтеграція.

Передавання особи в SDK#

Отримайте підписану особу зі свого бекенду, потім передайте 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#

Коли верифікація ввімкнена в агента, а підпис відсутній або хибний, бекенд виконує мовчазне пониження до анонімного: чат далі працює, visitor_id зберігається, а розмова прив’язується до анонімного контакту — але зв’язку з профілем немає й немає історії між пристроями. Якщо користувача «не впізнано», майже завжди справа в підписі: перевірте, що ви підписали userId (а не email чи JSON), використали правильний identity_secret і видали hex у нижньому регістрі. Якщо identity_secret агента порожній, верифікація вимкнена, і userId / email приймаються як є.

Ротація identity_secret — це, по суті, різкий перехід: кожен хеш, створений зі старим секретом, одразу перестає верифікуватися, тож уже залогінені користувачі мовчки відкочуються до анонімних, доки ваш бекенд не переобчислить і не надасть повторно їхній userHash із новим секретом. Змінюйте секрет лише тоді, коли можете оновити сторону підписування в тому ж вікні.