Верифікація особи
Упізнавайте залогінену людину й відновлюйте історію її розмов на різних пристроях, використовуючи підпис, який контролює ваш бекенд.
Навіщо верифікувати#
За замовчуванням SDK анонімний: він генерує стабільний visitor_id і тримає його в платформенному сховищі ключів (keystore). Цього достатньо для однієї розмови на одному пристрої. Щоб упізнати конкретного користувача, відновити історію при повторному вході чи на іншому пристрої й надійно прив’язати розмову до профілю контакту, бекенду потрібен доказ, що клієнт — це той, за кого себе видає. Якби SDK просто надсилав «я користувач 42», будь-хто міг би підмінити чужий ідентифікатор і читати чужий чат — тож Respondo вимагає криптографічний підпис, userHash, який може створити лише ваш бекенд.
Отримання секрету особи#
identity_secret — це секретний рядок, прив’язаний до вашого агента (AI-працівника, до якого підключений канал вашого віджета). Згенеруйте його в дашборді: Channels → Widget → Identity verification. Секрет лежить на агенті, тож він спільний для всіх каналів цього агента — і для вебвіджета, і для мобільного SDK. Він дає право підписувати особи, тож має жити лише на вашому бекенді й ніколи не постачатися в застосунку.
Формула userHash#
userHash — це HMAC-SHA256 над єдиним підписаним рядком особи, закодований як hex у нижньому регістрі:
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 у застосунок.
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))
}const crypto = require("crypto");
// Повертає userHash для передавання в Respondo.identify на мобільному клієнті.
function computeUserHash(identitySecret, userId) {
return crypto
.createHmac("sha256", identitySecret)
.update(userId, "utf8")
.digest("hex");
}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()<?php
// Повертає userHash для передавання в Respondo.identify на мобільному клієнті.
function computeUserHash(string $identitySecret, string $userId): string {
return hash_hmac('sha256', $userId, $identitySecret);
}Як хеш потрапляє в Respondo#
/identity не існує й реєструвати нічого не потрібно. userHash — це поле, яке їде в запитах, що SDK робить і так.Два хопи, і будуєте ви лише перший:
- Ваш бекенд → ваш застосунок. Доставляєте хеш як вам зручно. Найдешевше — додатковим полем у відповіді логіна/бутстрапа, яку ви й так віддаєте (зайвого запиту немає). Окремий ендпоінт на вашому власному бекенді (наприклад
POST /myapp/identity→{ userId, userHash }) працює не гірше. Respondo цього ендпоінта не надає — його пишете ви. - Ваш застосунок → Respondo. Це робить SDK. Після виклику
identifyхеш сам додається до кожного потрібного запиту, а бекенд перевіряє його щоразу.
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 сам собою марний.
identify не викличеться, і чат працюватиме анонімно. Це очікувана поведінка, а не помилка Respondo: 404 на вашому власному шляху — задача на вашому боці, а не зламана інтеграція.Передавання особи в SDK#
Отримайте підписану особу зі свого бекенду, потім передайте userHash у identify на будь-якій платформі:
Respondo.identify(
RespondoIdentity(userId = "42", email = "user@example.com", userHash = hash),
)Respondo.identify(
RespondoIdentity(userId: "42", email: "user@example.com", userHash: hash)
)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 із новим секретом. Змінюйте секрет лише тоді, коли можете оновити сторону підписування в тому ж вікні.