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.
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
| Mode | Cas d'usage typique | Authentification pour délimiter la session | Backend requis |
|---|---|---|---|
| Mode 1 - Public | FAQ site web, génération de leads, aide SaaS simple sans contexte par utilisateur | Aucune | Non |
| Mode 2 - Connecté | SaaS authentifié, support contextuel, automatisations | JWT 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 ⚡
-
Vérifie la signature avec la clé publique de l'agent (identifiée par kid)
-
Valide les claims :
- Horodatages (iat, exp) — durée de vie max 15 minutes
- Unicité de jti — évite les attaques par rejeu (stocké 15 min)
-
Émet un access token lié DPoP — cryptographiquement lié à la paire de clés éphémère de l'iframe
-
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
| Attribut | Description |
|---|---|
data-agent-id | Requis. ID de l'agent fourni par ATG. |
data-signed-params | Optionnel. 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-launcher | Optionnel. Position du lanceur de chat (bottom-right, bottom-left, floating, hidden). Par défaut : bottom-right. |
data-language | Optionnel. Langue de l'interface : en, fr. Par défaut : en. |
data-page-route | Optionnel. 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-json | Optionnel. 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-label | Optionnel. Label d'accessibilité pour le bouton du lanceur de chat (ex. « Ouvrir l'assistant de chat »). |
Description de data-theme-json :
| Nom du token | Description | Exemple de valeur |
|---|---|---|
color.brand | Couleur de marque principale | #6D28D9 |
color.bg | Couleur de fond du chat | #0B0B0F |
color.text | Couleur du texte principal | #F3F4F6 |
color.muted | Couleur du texte secondaire | #9CA3AF |
radius.sm, radius.lg | Rayon des coins pour boutons, cartes | 8px, 16px |
font.family | Stack de polices | Inter, system-ui, sans-serif |
shadow.elevation | Ombre des cartes / lanceur | 0 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
| Claim | Type | Description | Exemple / Notes |
|---|---|---|---|
kid | string | Key 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" |
alg | string | Algorithme : doit être "ES256" (ECDSA avec courbe P-256 et SHA-256). | "ES256" |
Claims du payload (requis)
| Claim | Type | Description | Exemple / Notes |
|---|---|---|---|
iat | number (secondes Unix) | Heure d'émission du jeton. Utilisé pour détecter dérive d'horloge ou rejeu. | 1739298000 |
exp | number (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 |
jti | string (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)
| Claim | Type | Description | Exemple / Notes |
|---|---|---|---|
external_user_ref | string | Ré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" |
entitlements | object (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_metadata | object (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 :
-
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).
-
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.
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 :
- Générez une nouvelle paire de clés de signature et donnez-lui un nouveau
kid(ex.key-2025-02). - Ajoutez la nouvelle clé publique dans la console ATG en gardant l'ancienne jusqu'à expiration des jetons signés avec elle (≤ 15 min).
- 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. ✨