Cette page est une traduction automatique. Pour les informations de référence, consultez la version anglaise.

Intégrer ATG Embedded dans votre webapp

Guide technique pour intégrer ATG Embedded dans votre webapp : isolation iframe, modes d'intégration (public vs connecté), widget, authentification et intégration pas à pas.

6 min de lecture

Vue d'ensemble

ATG Embedded s'exécute dans une iframe isolée hébergée sur app.askthisguy.com, ce qui garantit la confidentialité des données, une sécurité robuste et des mises à jour sans effort. 🔒

Modes d'intégration

ModeCas d'usage typiqueAuthentification pour délimiter la sessionBackend requis
Mode 1 - PublicFAQ site web, génération de leads, aide SaaS simple sans contexte par utilisateurAucuneNon
Mode 2 - ConnectéSaaS authentifié, support contextuel, automatisationsJWT signé côté serveur avec TTL court✅ Oui

Concepts clés 🔑

Pour les deux modes

Widget (widget.js)

Script léger fourni par ATG que vous intégrez sur votre site.

Il injecte une iframe pointant vers https://app.askthisguy.com, crée le lanceur de chat via le Shadow DOM et communique avec l'iframe via postMessage.

Isolation de l'iframe

Toute l'interface et les données du chat se trouvent dans une iframe cross-origin (app.askthisguy.com) sous la politique Same-Origin du navigateur :

  • Votre page ne peut pas lire les jetons ATG
  • ATG ne peut pas accéder à vos cookies ni à vos scripts

Shadow DOM

Évite les conflits CSS/JS avec votre site.

Access token

Pour maintenir les sessions de chat avec les utilisateurs, ATG s'assure que l'iframe détient en mémoire un jeton porteur à courte durée de vie, lié au DPoP, et l'envoie en Authorization: DPoP \<access\> avec l'en-tête approprié.

Ce mécanisme permet de maintenir une session sur des navigateurs comme Safari où les cookies tiers et les cookies partitionnés sont bloqués.

Pour le mode 2 uniquement

Paramètres signés

Le seul travail backend requis consiste à développer un endpoint simple qui crée un JSON Web Token (JWT) signé avec votre clé privée.

Exemple de JWT avec le minimum requis :

  // Header
  {
    "alg": "ES256",
    "kid": "prod-key-2024-01"
  }

  // Payload (minimal requis)
  {
    "iat": 1739298000,
    "exp": 1739298900,
    "jti": "550e8400-e29b-41d4-a716-446655440000"
  }

Vous pourrez téléverser une clé publique dans la console d'administration ATG pour qu'ATG puisse décoder le JWT et ouvrir une session de chat avec l'utilisateur. Vous conservez la clé privée sur vos serveurs.

Vous pouvez transmettre d'autres paramètres à ATG pour définir les droits et le contexte de l'utilisateur pour cette session. Consultez l'annexe pour la description de tous les paramètres supportés.

Architecture

Mode 1 - Flux public

Loading diagram…

Mode 2 - Connecté

Loading diagram…

Une fois la session établie, le widget envoie les messages utilisateur à ATG sur un canal sécurisé (SSE/HTTPS), et ATG renvoie en temps réel les tokens de l'assistant à l'iframe, qui affiche l'interface de chat.

Loading diagram…

Étapes d'intégration (les deux modes)

Étape 1 : Configurer votre agent dans la console d'administration ATG ⚙️

Créer votre agent et configurer les connaissances

Configurez d'abord votre agent dans la console d'administration avec vos instructions et vos connaissances.

Voir Configurer les agents pour plus de détails. C'est en général pris en charge par l'équipe fonctionnelle / utilisateurs métier. Vous pourrez aussi tester le comportement de l'agent dans le Playground intégré à la console d'administration.

Origines autorisées (Allow-Listed Origins)

Dans la console d'administration, indiquez à ATG les origines exactes autorisées à intégrer le widget (ex. https://yourapp.com, https://staging.yourapp.com).

Cela sera appliqué automatiquement via des contrôles à l'exécution et les en-têtes CSP (Content Security Policy) sur l'iframe, pour que le chat ne soit intégrable que sur les domaines approuvés.

ATG définira sa CSP (Content-Security-Policy) avec une directive frame-ancestors basée sur vos origines autorisées :

Content-Security-Policy:
  frame-ancestors [https://yourapp.com](https://yourapp.com) [https://staging.yourapp.com](https://staging.yourapp.com);

Étape 2 : Vérifier que votre site ne bloque pas ATG

Si votre site utilise une Content-Security-Policy (CSP) stricte qui bloque par défaut les iframes ou scripts externes, vous devez autoriser explicitement le widget et l'iframe ATG.

Pour vérifier si votre site utilise une CSP, vous pouvez utiliser une commande curl par exemple :

curl -I [https://yourwebsite.com](https://yourwebsite.com) | grep -i content-security-policy

Si la commande ne retourne rien ou seulement une règle frame-ancestors (cas le plus fréquent), vous n'avez pas besoin d'étendre l'en-tête CSP, passez à l'étape suivante.

Si elle retourne des CSP strictes du type Content-Security-Policy: default-src 'self'; script-src 'self'; frame-src 'none';, ajoutez ou étendez votre en-tête CSP ainsi :

Content-Security-Policy:
  script-src 'self' [https://app.askthisguy.com](https://app.askthisguy.com);
  frame-src [https://app.askthisguy.com](https://app.askthisguy.com);

Cet en-tête est défini sur votre propre serveur ou CDN (par votre équipe tech/ops).

Il indique au navigateur que votre page est autorisée à charger le script et l'iframe ATG.

Étape 3 : Ajouter le script du widget 💻

Vous trouverez dans la console d'administration ATG un code JS simple à ajouter vers la fin du \<body\> de chaque page. Il ressemblera à :

  <!-- Charger la librairie jose -->
  <script type="module">
    import * as jose from 'https://cdn.jsdelivr.net/npm/jose@5.2.3/+esm';
    window.jose = jose;
  </script>

  <!-- Charger le widget (sans paramètres signés) -->
  <script async
    src="https://app.askthisguy.com/widget.js"
    data-agent-id="YOUR_AGENT_ID"
    data-language="fr"
    data-launcher="bottom-right">
  </script>

Consultez l'annexe pour la description détaillée de tous les paramètres supportés par le widget.

Étapes supplémentaires pour le mode 2 🔐

1. Implémenter /embed/presign 🛠️

Pour activer le mode 2, vous devez implémenter un endpoint simple /embed/presign. Vous pouvez changer ce nom si vous préférez.

Cet endpoint doit :

  • Être un endpoint POST
  • Vérifier que l'utilisateur est authentifié dans votre app
  • Si oui, retourner un JWT de paramètres signés à courte durée de vie avec un TTL < 15 min
  • Être signé avec ES256 et inclure un en-tête kid

Nous recommandons aussi de n'accepter que les requêtes same-origin sur /embed/presign.

Corps de la réponse :

  // Payload (avec contexte optionnel)
  {
    "iat": 1739298000,
    "exp": 1739298900,
    "jti": "550e8400-e29b-41d4-a716-446655440000",
    "external_user_ref": "user_12345",
    "entitlements": {
      "plan": "premium",
      "features": ["export", "analytics"]
    },
    "context_metadata": {
      "department": "sales",
      "region": "EU"
    }
  }

Consultez l'annexe pour la description de tous les paramètres supportés.

2. Configurer la clé publique pour qu'ATG décode le JWT 🔑

Dans la console d'administration ATG, allez dans les paramètres de sécurité de votre agent et saisissez la clé publique que ATG utilisera pour décoder le JWT signé avec votre clé privée dans /embed/presign.

3. Fournir le JWT au widget 📤

Le code JS à ajouter sur votre site sera légèrement différent pour le mode 2.

Depuis la console d'administration, vous pouvez télécharger le dernier code JS à insérer dans votre page ou via votre tag manager. Le code ressemblera à :

<!-- ÉTAPE 1 : Charger la librairie jose (requise par le widget pour la signature JWT) -->
  <script type="module">
    import * as jose from 'https://cdn.jsdelivr.net/npm/jose@5.2.3/+esm';
    window.jose = jose;
  </script>

  <!-- ÉTAPE 2 : Implémenter le callback getSignedParams (appelé par le widget pour
  l'init de session et la rotation) -->
  <script>
    window.ATG = window.ATG || {};

    // Appelé par le widget quand il a besoin de paramètres signés frais (init et refresh)
    window.ATG.getSignedParams = async () => {
      try {
        // Appeler votre endpoint presign backend
        const response = await fetch("/embed/presign", {
          method: "POST",
          credentials: "include" // Inclure les cookies de session pour l'authentification
        });

        if (!response.ok) {
          throw new Error(`Presign failed: ${response.status}`);
        }

        const data = await response.json();

        // Retourner la chaîne JWT (pas l'objet)
        // Votre backend doit retourner : { "signed_jwt": "eyJ..." }
        return data.signed_jwt;

      } catch (error) {
        console.error("Failed to get signed params:", error);
        throw error; // Laisser le widget ATG gérer l'erreur
      }
    };
  </script>

  <!-- ÉTAPE 3 : Charger le widget ATG avec la configuration -->
  <script async
    src="https://app.askthisguy.com/widget.js"
    data-agent-id="YOUR_AGENT_ID"
    data-signed-params="true"
    data-language="fr"
    data-launcher="bottom-right"
    data-page-route="/plans"
    data-theme-json='{"color.brand":"#6D28D9"}'
    data-aria-label="Ouvrir le chat d'assistance">
  </script>

Le widget appellera window.ATG.getSignedParams() pour obtenir le JWT.

Adaptez et intégrez ce code selon vos standards de sécurité :

  • Assurez-vous de fournir window.ATG.getSignedParams()
  • Définissez-le une seule fois ; protégez contre la ré-injection dans les SPA
  • Privilégiez un nonce CSP

Si vous utilisez un tag manager avec deux tags (un pour le callback et un pour widget.js), assurez-vous d'utiliser le séquencement des tags pour que le callback se charge en premier.

4. Ce qu'ATG fait avec les paramètres signés ⚡

  1. Vérifie la signature avec la clé publique de l'agent (identifiée par kid)

  2. Valide les claims :

  • Horodatages (iat, exp) — durée de vie max 15 minutes
  • Unicité de jti — évite les attaques par rejeu (stocké 15 min)
  1. Émet un access token lié DPoP — cryptographiquement lié à la paire de clés éphémère de l'iframe

  2. Fournit le contexte de session — les claims optionnels (external_user_ref, entitlements, context_metadata) sont disponibles pour l'agent pour la personnalisation

Annexe 📚

Paramètres du widget

AttributDescription
data-agent-idRequis. ID de l'agent fourni par ATG.
data-signed-paramsOptionnel. Booléen (true ou false). Active l'authentification par paramètres signés. Nécessite l'implémentation du callback window.ATG.getSignedParams. Par défaut : false.
data-launcherOptionnel. Position du lanceur de chat (bottom-right, bottom-left, floating, hidden). Par défaut : bottom-right.
data-languageOptionnel. Langue de l'interface : en, fr. Par défaut : en.
data-page-routeOptionnel. Route canonique de la page courante (ex. /plans). Utile si vous configurez des instructions d'agent qui en tiennent compte pour le contenu contextuel.
data-theme-jsonOptionnel. Objet JSON définissant des tokens visuels (couleur de marque, polices, rayon des coins). Permet de styliser rapidement l'assistant. Exemple : {"color.brand":"#6D28D9","radius.lg":"12px"}
data-aria-labelOptionnel. Label d'accessibilité pour le bouton du lanceur de chat (ex. « Ouvrir l'assistant de chat »).

Description de data-theme-json :

Nom du tokenDescriptionExemple de valeur
color.brandCouleur de marque principale#6D28D9
color.bgCouleur de fond du chat#0B0B0F
color.textCouleur du texte principal#F3F4F6
color.mutedCouleur du texte secondaire#9CA3AF
radius.sm, radius.lgRayon des coins pour boutons, cartes8px, 16px
font.familyStack de policesInter, system-ui, sans-serif
shadow.elevationOmbre des cartes / lanceur0 8px 24px rgba(0,0,0,0.25)

Paramètres de l'endpoint

Le JWT signé par /embed/presign pour démarrer une session doit comporter deux parties : header et claims (payload).

Header

ClaimTypeDescriptionExemple / Notes
kidstringKey ID : identifie quelle clé publique utiliser pour la vérification de signature. Doit correspondre à une clé enregistrée pour votre agent dans la console ATG."prod-key-2024-01"
algstringAlgorithme : doit être "ES256" (ECDSA avec courbe P-256 et SHA-256)."ES256"

Claims du payload (requis)

ClaimTypeDescriptionExemple / Notes
iatnumber (secondes Unix)Heure d'émission du jeton. Utilisé pour détecter dérive d'horloge ou rejeu.1739298000
expnumber (secondes Unix)Expiration : date d'expiration absolue de ce jeton de paramètres signés. Doit être courte (≤ 15 min). ATG refuse les jetons expirés ou à trop longue durée de vie.1739298900
jtistring (UUID/aléatoire)JWT ID : nonce unique pour ce jeton. Doit être aléatoire à chaque émission.550e8400-e29b-41d4-a716-446655440000

Claims du payload (optionnels)

ClaimTypeDescriptionExemple / Notes
external_user_refstringRéférence ou ID utilisateur externe de votre système. Peut servir à identifier l'utilisateur dans les instructions de l'agent ou les logs."user_12345"
entitlementsobject (JSON)Droits ou permissions de l'utilisateur. Utilisable par l'agent pour la logique de contrôle d'accès.{"plan": "premium", "features": ["export"]}
context_metadataobject (JSON)Métadonnées de contexte supplémentaires sur la session ou l'utilisateur.{"department": "sales", "region": "EU"}

FAQ ❓

ATG renouvelle automatiquement le jeton de session 60 secondes avant expiration pour éviter les coupures de chat :

  1. Configuration du timer : À l'initialisation de la session, un timer de rotation est planifié selon la valeur expires_in (en général 10 minutes).

  2. Demande de pré-rotation (si paramètres signés activés) :

  • 60 secondes avant l'expiration du jeton, l'iframe envoie un postMessage au widget : { type: "ATG_REQUEST_SIGNED_PARAMS_FOR_ROTATION" }
  • Le widget appelle automatiquement votre callback window.ATG.getSignedParams() pour obtenir un nouveau JWT signé.
  • Votre callback doit appeler l'endpoint presign de votre backend et retourner le nouveau JWT.
  • Le widget renvoie le JWT à l'iframe et l'iframe renouvelle la session avec le serveur ATG.

Non, nous n'utilisons pas de cookies tiers (ils seraient bloqués). Pour notre access token, nous utilisons JWT + preuve DPoP.

Chaque JWT de paramètres signés inclut un kid (Key ID) dans son header.

ATG utilise cette valeur pour retrouver immédiatement la bonne clé publique que vous avez téléversée dans la console.

Lors d'une rotation de clés :

  1. Générez une nouvelle paire de clés de signature et donnez-lui un nouveau kid (ex. key-2025-02).
  2. Ajoutez la nouvelle clé publique dans la console ATG en gardant l'ancienne jusqu'à expiration des jetons signés avec elle (≤ 15 min).
  3. Signez les nouveaux jetons avec le nouveau kid, puis retirez l'ancienne clé.

ATG vérifie chaque jeton avec la clé publique qui correspond à son kid, donc la rotation se fait sans interruption ni reconfiguration manuelle. ✨