Documentatie

Identiteitsverificatie

Herken een ingelogde persoon en herstel zijn gespreksgeschiedenis over apparaten heen, met een handtekening die je backend beheert.

Waarom verifiëren#

Standaard is de SDK anoniem: hij genereert een stabiele visitor_id en bewaart die in de keystore van het platform. Dat is genoeg voor één gesprek op één apparaat. Om een specifieke gebruiker te herkennen, geschiedenis te herstellen bij opnieuw inloggen of op een ander apparaat, en een gesprek betrouwbaar aan een contactprofiel te koppelen, heeft de backend bewijs nodig dat de client is wie hij beweert te zijn. Als de SDK simpelweg "Ik ben gebruiker 42" zou sturen, zou iedereen een andere id kunnen spoofen en de chat van iemand anders kunnen lezen — daarom vereist Respondo een cryptografische handtekening, userHash, die alleen je backend kan produceren.

Het identity secret verkrijgen#

De identity_secret is een geheime string die gekoppeld is aan je agent (de AI-werker waarmee je widgetkanaal is verbonden). Genereer hem in het dashboard onder Channels → Widget → Identity verification. Omdat hij op de agent leeft, delen alle kanalen achter die agent hetzelfde secret — zowel de webwidget als de mobiele SDK. Hij verleent het recht om identiteiten te ondertekenen, dus hij mag alleen op je backend leven en mag nooit met de app worden meegeleverd.

De userHash-formule#

userHash is een HMAC-SHA256 over één enkele ondertekende identiteitsstring, gecodeerd als kleine-letter-hex:

Formuletext
userHash = HMAC_SHA256( identity_secret, payload )

payload = userId          // als userId is ingesteld
        = email           // anders, als email is ingesteld
        = (invalid)       // als beide leeg zijn, is er niets om te ondertekenen
  • Het secret is de HMAC-sleutel; de identiteitsstring is het bericht — niet andersom.
  • Onderteken precies één string — de ruwe userId (of email), zonder salt of JSON-wrapper.
  • Als je zowel userId als email meegeeft, onderteken dan de userId (die heeft voorrang).
  • De uitvoer is hex (64 tekens voor SHA-256), geen base64.

Backend-voorbeelden#

Bereken de handtekening op je backend en geef de afgeronde userHash aan de app.

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

// HMAC_SHA256(identity_secret, userId) als kleine-letter-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");

// Retourneert de userHash om door te geven aan Respondo.identify op de mobiele client.
function computeUserHash(identitySecret, userId) {
  return crypto
    .createHmac("sha256", identitySecret)
    .update(userId, "utf8")
    .digest("hex");
}
Pythonpython
import hmac
import hashlib

# Retourneert de userHash om door te geven aan Respondo.identify op de mobiele client.
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
// Retourneert de userHash om door te geven aan Respondo.identify op de mobiele client.
function computeUserHash(string $identitySecret, string $userId): string {
    return hash_hmac('sha256', $userId, $identitySecret);
}

Hoe de hash bij Respondo terechtkomt#

Respondo heeft geen identity-endpoint. Er is geen /identity-route om aan te roepen en er valt niets te registreren. userHash is een veld dat meelift op de verzoeken die de SDK toch al doet.

Twee stappen, en alleen de eerste moet je zelf bouwen:

  1. Je backend → je app. Je levert de hash aan zoals je zelf wilt. De goedkoopste optie is een extra veld in de login-/bootstrap-response die je toch al teruggeeft — geen extra round trip. Een eigen endpoint op je eigen backend (bijvoorbeeld POST /myapp/identity dat { userId, userHash } teruggeeft) werkt net zo goed. Respondo host dat endpoint niet — jij bouwt het.
  2. Je app → Respondo. Dat wordt voor je geregeld. Zodra je identify aanroept, hangt de SDK de hash aan elk relevant verzoek en verifieert de backend hem elke keer opnieuw.
Waar de SDK hem plaatst (ter referentie — je stuurt deze niet met de hand)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 (subscribe/identify JSON frames after connect — not in the handshake 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

De hash wordt bij elk verzoek opnieuw gecontroleerd en niet één keer ingewisseld voor een sessie — precies daarom is een gestolen userId op zichzelf nutteloos.

Als het afleverendpoint op jouw backend nog niet gebouwd is, geeft het verzoek van je eigen app een 404, identify wordt nooit aangeroepen en loopt de chat anoniem. Dat is verwacht gedrag, geen fout van Respondo — een 404 op je eigen pad is een to-do aan jouw kant, geen kapotte integratie.

De identiteit doorgeven aan de SDK#

Haal de ondertekende identiteit op van je backend en geef de userHash vervolgens door aan identify op elk platform:

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

Gedrag bij ongeldige userHash#

Wanneer verificatie is ingeschakeld op de agent en de handtekening ontbreekt of onjuist is, voert de backend een stille downgrade naar anoniem uit: de chat werkt nog steeds, de visitor_id blijft behouden, en het gesprek wordt gekoppeld aan het anonieme contact — maar er is geen koppeling met het profiel en geen geschiedenis tussen apparaten. Als een gebruiker "niet wordt herkend", ligt het bijna altijd aan de handtekening: controleer dat je de userId hebt ondertekend (niet email of JSON), het juiste identity_secret hebt gebruikt en kleine-letter-hex hebt uitgegeven. Als het identity_secret van de agent leeg is, staat verificatie uit en worden userId / email as-is geaccepteerd.

Het roteren van het identity_secret is in feite een harde omschakeling: elke hash die met het oude secret is gemaakt, stopt onmiddellijk met verifiëren, dus reeds ingelogde gebruikers vallen stil terug naar anoniem totdat je backend hun userHash herberekent en opnieuw aanlevert met het nieuwe secret. Roteer het secret alleen wanneer je de ondertekenende kant in hetzelfde venster kunt bijwerken.