Перейти до основного вмісту
ДокументаціяІдентичність і підписані сесії

Захистіть ідентичність користувача в DobroDesk SDK

Використовуйте endpoint бекенда хоста для короткоживучих токенів ідентичності клієнта у вебі та нативних інтеграціях.

На цій сторінці

Клієнти можуть відновити власний контекст підтримки без розкриття signing secret або support API token у браузері чи бандлі застосунку.

Зберігайте підписування на бекенді

Ваш бекенд автентифікує поточного клієнта, підписує короткоживучий DobroDesk customer identity JWT для вибраної інтеграції та повертає його з endpoint, захищеного сесією хоста. Відповідь endpoint для мобільних обгорток — JSON з рядком authorizationToken.

SDK не створює цей JWT, а loadDobroDeskToken не є функцією SDK. У прикладах нижче це функція, яку надає хост. Ніколи не додавайте JWT signing secret, DobroDesk support API token або довговічні облікові дані сервісу до браузерного JavaScript, мобільного бандла чи публічного репозиторію.

Вебвіджет також підтримує анонімну сесію. Нативні SDK вимагають підписану ідентичність клієнта до мережевих операцій і відкриття віджета. Нативні запити передають ідентичність як Authorization: Bearer... з x-dobrodesk-client: native-v1 і не надсилають browser Origin. Після старту сесії нативний рушій володіє отриманим session proof і передає його як x-dobrodesk-session-token. Хост не має створювати або замінювати цей заголовок.

Endpoint хоста та провайдери SDK
// This function belongs to your application. The route is your backend route.
async function loadDobroDeskToken(): Promise<string> {
  const response = await fetch("/your-backend/dobrodesk-token", {
    method: "POST",
    credentials: "include",
    headers: { Accept: "application/json" },
  });
  if (!response.ok) throw new Error("Customer token request failed");
  const body = (await response.json()) as { authorizationToken?: unknown };
  if (typeof body.authorizationToken !== "string" || !body.authorizationToken)
    throw new Error("Customer token response is invalid");
  return body.authorizationToken;
}

// Web can remain anonymous or apply the token after host login.
widget.setIdentityToken(await loadDobroDeskToken());

// React Native, NativeScript and Capacitor use the signed native shape.
const config = {
  apiOrigin: "https://dobrodesk.com",
  integrationId: "wgt_0123456789abcdef0123456789abcdef",
  accountScope: currentCustomer.id,
  credentialProvider: async () => ({
    authorizationToken: await loadDobroDeskToken(),
  }),
};

Налаштуйте signing secret і claims

У Admin > Channels > Website widgets відкрийте інтеграцію віджета, встановіть identity mode у Require a signed logged-in user і використайте Copy identity secret. Збережіть скопійований secret конкретної інтеграції у менеджері секретів бекенда разом із публічним Integration ID. Secret не має потрапляти у браузер, мобільний бандл або публічний репозиторій. Використовуйте його як ключ підпису HS256.

Підписуйте три частини HS256 JWT з typ JWT. Обов'язкові claims: iss = dobrodesk-widget:{integrationId}, aud = публічний Integration ID, sub = стабільний ID клієнта, що не є email, iat = поточні Unix seconds і exp не більш ніж через 15 хвилин після iat. Verifier дозволяє 60 секунд розбіжності годинників. Необов'язкові claims: name, email, email_verified: true і jti. Встановлюйте email_verified лише після перевірки адреси хостом.

Серверне підписування через Web Crypto
const textEncoder = new TextEncoder();

const base64url = (bytes: Uint8Array) => {
  let binary = "";
  for (const byte of bytes) binary += String.fromCharCode(byte);
  return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
};

// secretStore is your backend secret manager. Never run this in browser code.
export async function createDobroDeskIdentityToken(user: {
  id: string;
  email?: string;
  emailVerified?: boolean;
  name?: string;
}) {
  const integrationId = await secretStore.get("DOBRODESK_WIDGET_ID");
  const identitySecret = await secretStore.get("DOBRODESK_WIDGET_IDENTITY_SECRET");
  const now = Math.floor(Date.now() / 1000);
  const encode = (value: unknown) =>
    base64url(textEncoder.encode(JSON.stringify(value)));
  const header = encode({ alg: "HS256", typ: "JWT" });
  const payload = encode({
    iss: `dobrodesk-widget:${integrationId}`,
    aud: integrationId,
    sub: user.id,
    iat: now,
    exp: now + 5 * 60,
    ...(user.email
      ? {
          email: user.email,
          ...(user.emailVerified === true ? { email_verified: true } : {}),
        }
      : {}),
    ...(user.name ? { name: user.name } : {}),
  });
  const key = await crypto.subtle.importKey(
    "raw",
    textEncoder.encode(identitySecret),
    { name: "HMAC", hash: "SHA-256" },
    false,
    ["sign"],
  );
  const signature = base64url(
    new Uint8Array(
      await crypto.subtle.sign("HMAC", key, textEncoder.encode(`${header}.${payload}`)),
    ),
  );
  return `${header}.${payload}.${signature}`;
}

Свідомо прив'язуйте й очищайте ідентичність

Задайте accountScope як стабільний ідентифікатор клієнта або акаунта хоста, що не містить секретів. Він ізолює довговічний нативний стан сесії та outbox. Не використовуйте один scope для кількох авторизованих клієнтів.

У Flutter, React Native, NativeScript або Capacitor викликайте logout до завершення сесії хоста або зміни accountScope. Прямі iOS та Android клієнти натомість надають resetSession: скиньте цей клієнт і створіть новий для наступного акаунта. Викликайте resetSession, коли клієнт навмисно відкидає поточну розмову, але залишається авторизованим. Оновлення токена не є перемиканням акаунта й має використовувати той самий account scope.

Відхиляйте небезпечні стани токена

  1. Відхиляйте порожній, пошкоджений, прострочений або призначений іншому клієнту токен у endpoint хоста, а не повертайте облікові дані підтримки.
  2. Сприймайте помилку SDK 401 або session-expired як запит на свіжий токен для того самого акаунта. Не перемикайте accountScope непомітно й не створюйте нову сесію.
  3. Якщо logout запитано під час очікування токена, ігноруйте пізній токен і зберігайте ізоляцію наступного акаунта від попередньої сесії.