# Weryfikacja tożsamości zalogowanych użytkowników

> Rozpoznawaj zalogowanych użytkowników w widżecie czatu: klucz weryfikacji, liczenie userHash w Node.js, PHP i Python, zweryfikowany e-mail i wylogowanie.

Jeśli użytkownicy logują się na twojej stronie lub w aplikacji, widżet może ich rozpoznać. Wtedy widzą swoje rozmowy na każdym urządzeniu, a zespół widzi jeden kontakt zamiast kilku anonimowych.

## Po co podpis

Przeglądarce nie można ufać: każdy może wywołać `identify` z cudzym e-mailem. Dlatego twój serwer liczy `userHash`, podpis HMAC-SHA256 z kluczem weryfikacji, którego przeglądarka nigdy nie widzi.

## Klucz weryfikacji

Klucz znajdziesz w ustawieniach widżetu czatu, na karcie „Weryfikacja tożsamości”. Widzą go i zmieniają tylko właściciele.

- Trzymaj klucz tylko na serwerze, np. w zmiennej `SUPPORT_IDENTITY_SECRET`. Nigdy nie wstawiaj go do kodu przeglądarki.
- Po utworzeniu nowego klucza stary działa jeszcze 24 godziny, żebyś zdążył zaktualizować serwer.

![Ustawienia weryfikacji tożsamości z ukrytym kluczem](https://hrc.lt/screens/pl/project-identity.desktop.1600.b6aee83a.webp)

## Co podpisać

Podpis liczony jest z tekstu `v1:<ID>:<e-mail>`. E-mail bez spacji na brzegach i małymi literami; brakująca część zostaje pusta.

```text
v1:<externalId>:<e-mail bez spacji na brzegach, małymi literami>

v1:12345:jonas@example.com   ID i e-mail
v1:12345:                    tylko ID
v1::jonas@example.com        tylko e-mail, wymaga ustawienia
                             „Moja aplikacja weryfikuje adresy e-mail”
```

`userHash` to HMAC-SHA256 tego tekstu z kluczem weryfikacji, zapisany jako 64 znaki szesnastkowe.

## Kod dla serwera

Node.js:

```js
// Node.js (Express): twój endpoint, tylko dla zalogowanego użytkownika
import { createHmac } from 'node:crypto';

app.get('/api/support-hash', requireLogin, (req, res) => {
  const user = req.user;
  const email = (user.email ?? '').trim().toLowerCase();
  const canonical = `v1:${user.id ?? ''}:${email}`;
  const userHash = createHmac('sha256', process.env.SUPPORT_IDENTITY_SECRET)
    .update(canonical)
    .digest('hex');
  res.json({ userHash });
});
```

PHP:

```php
<?php
// PHP: mb_strtolower, nie strtolower, żeby Ł i Ż też były małe
$email = mb_strtolower(trim($user->email ?? ''), 'UTF-8');
$canonical = 'v1:' . ($user->id ?? '') . ':' . $email;
$secret = getenv('SUPPORT_IDENTITY_SECRET');
$userHash = hash_hmac('sha256', $canonical, $secret);
```

Python:

```python
# Python
import hashlib
import hmac
import os

user_id = "" if user.id is None else str(user.id)
email = (user.email or "").strip().lower()
canonical = f"v1:{user_id}:{email}"
secret = os.environ["SUPPORT_IDENTITY_SECRET"].encode()
user_hash = hmac.new(secret, canonical.encode(), hashlib.sha256).hexdigest()
```

## Kod dla przeglądarki

Zawsze przekazuj `externalId` jako tekst: liczba jest pomijana.

```js
// W przeglądarce: poproś swój serwer o podpis zalogowanego użytkownika
const { userHash } = await fetch('/api/support-hash', {
  credentials: 'include',
}).then((r) => r.json());
HrcWidget('identify', {
  externalId: String(user.id ?? ''),
  email: user.email,
  name: user.name,
  userHash,
});

// Przy wylogowaniu
HrcWidget('reset');
```

Z `identify` możesz przekazać też pola profilu, zobacz [Profil odwiedzającego](https://hrc.lt/pl/docs/widget/visitor-profile).

## „Moja aplikacja weryfikuje adresy e-mail”

Włącz tylko wtedy, gdy twoja aplikacja sprawdza, że e-mail należy do użytkownika (wysyła kod lub link). Wtedy podpisany e-mail łączy e-maile i rozmowy tej samej osoby w jeden kontakt we wszystkich widżetach czatu i skrzynkach pocztowych.

Dopóki to ustawienie jest wyłączone, zawsze przekazuj `externalId` użytkownika. Podpisany e-mail bez ID jest odrzucany z błędem `IDENTITY_INVALID`, a e-mail pozostaje niezweryfikowany, dopóki osoba nie odpowie na naszą wiadomość.

## Tylko zalogowani

Tryb „Tylko zalogowani” pozwala pisać tylko rozpoznanym użytkownikom. Anonimowa sesja nie może wysyłać wiadomości ani zmieniać profilu (`IDENTITY_REQUIRED`).

## Sprawdź podpis

W ustawieniach jest pole do sprawdzenia obliczonej wartości: wpisz ID, e-mail i wartość z serwera, a aplikacja powie, czy pasuje. Sprawdzenie odbywa się na serwerze, klucz nie trafia do przeglądarki. Jeśli nie pasuje, sprawdź, czy e-mail jest małymi literami i czy używasz klucza tego widżetu.

Błąd widzisz też na swojej stronie: `HrcWidget('on', 'identify-failed', ...)` dostaje kod, nigdy sam podpis.

## Wylogowanie

Gdy użytkownik się wylogowuje, wywołaj `HrcWidget('reset')`. Widżet zapomni sesję i następna osoba na tym samym urządzeniu nie zobaczy cudzych rozmów.
