SSO sans état

Le principe du SSO sans état est simple : chaque fois que l'embed se charge, vous envoyez les données de l'utilisateur courant dans les attributs suivants :

  • sso-user : les données de l'utilisateur au format JSON encodé en base64
  • sso-hash: Hash HMAC de sso-user, créé avec votre clé privée SSO. Utilisé pour valider l'authenticité des données de l'utilisateur.

Les embeds suivants prennent en charge ces attributs :

Prérequis

  • Installation terminée
  • Période d'essai ou forfait Business activé sur votre compte
  • Un backend capable de générer les données de l'utilisateur et le hash HMAC

Activer le SSO sans état

  • Allez dans la console → Paramètres → Authentification unique
  • Activez le SSO
  • Générez une clé privée
  • Ajoutez votre URL de connexion
  • Enregistrez
Activer le SSO sans état

Si vous avez une fenêtre contextuelle de connexion au lieu d'une URL, laissez l'URL de connexion vide et utilisez l'événement auth:login:clicked pour ouvrir la fenêtre.

Configuration du frontend

Pour configurer le SSO sans état, vous devez définir les attributs sso-user et sso-hash dans l'embed. Voici un exemple avec un embed de commentaires :

<hyvor-talk-comments
	...other-props
	sso-user="données utilisateur encodées en JSON puis en base64"
	sso-hash="hash HMAC"
></hyvor-talk-comments>

Ou, avec JavaScript :

const comments = document.createElement('hyvor-talk-comments');
comments.setAttribute('sso-user', 'données utilisateur encodées en JSON puis en base64');
comments.setAttribute('sso-hash', 'hash HMAC');

Initialisation synchrone ou asynchrone

Si votre site web est rendu à l'aide de modèles avec traitement côté backend (par exemple, des modèles PHP), vous pouvez calculer les données et le hash au moment du rendu du modèle, puis les afficher directement dans le code HTML

<hyvor-talk-comments
	...other-props
	sso-user="<?= $userData ?>"
	sso-hash="<?= $hash ?>"
></hyvor-talk-comments>

Si vous avez une application monopage (SPA), vous devrez créer un nouveau point de terminaison d'API (ex. : /hyvor-talk-sso) pour générer les données et le hash dans votre backend. Appelez ensuite ce point de terminaison pour obtenir le hash, puis affichez l'embed de manière asynchrone.

const comments = document.createElement('hyvor-talk-comments');
const ssoData = await fetch('/hyvor-talk-sso').then((res) => res.json());

comments.ssoUser = ssoData.user;
comments.ssoHash = ssoData.hash;

// enfin, ajouter l'élément au DOM
document.body.appendChild(comments);

Générer les données utilisateur et le hash HMAC

Les exemples suivants sont écrits en JavaScript/Node.

Vous trouverez des exemples pour d'autres langages dans le dépôt hyvor-talk-examples.

Étape 1 : vérifier si l'utilisateur est connecté

if (isUserLoggedIn()) {
}
Gérer les utilisateurs non authentifiés :

Si l'utilisateur n'est pas connecté, vous pouvez arrêter tout autre traitement. Dans les composants, définissez sso-user et sso-hash avec des valeurs vides :

  • sso-user="" en HTML
  • comments.setAttribute('sso-user', null) en JavaScript (ou toute autre valeur vide)
  • Ou, ne définissez simplement pas du tout les attributs SSO

Étape 2 : créer l'objet de données utilisateur

En général, vous avez une représentation de l'utilisateur dans votre système sous forme d'objet ou de modèle. Convertissez-la maintenant en un objet (ou dictionnaire) que Hyvor Talk peut « comprendre ».

// voici l'utilisateur de votre système
const user = getUser();

// créer un objet que Hyvor Talk comprend
let userData = {
	timestamp: Math.floor(Date.now() / 1000),

	id: user.id,
	name: user.fullname,
	email: user.email,
	title: user.title,
	picture_url: user.picture,
	website_url: user.website,
	bio: user.bio,
	location: user.location,

	badge_ids: [1, 2]
};

Propriétés de l'objet de données utilisateur

Clé
Description
Type
Longueur max.
timestamp*
Timestamp UNIX, en secondes, de création de l'objet.
integer
id*
Un ID unique enregistré dans votre base de données pour chaque utilisateur. Hyvor Talk l'utilise pour identifier chaque utilisateur.
integer ou string
128
name*
Nom d'affichage
string
50
email*
E-mail, doit être unique pour chaque utilisateur
string
256
title
Titre de l'utilisateur
string
256
picture_url
URL complète de la photo de profil
string
1024
website_url
URL complète du site web ou de la page de profil de l'utilisateur
string
1024
bio
Une courte biographie
string
255
location
Pays ou ville de l'utilisateur
string
50
badge_ids
IDs des badges associés à l'utilisateur.
integer[] ou { add?: integer[], remove?: integer[] }
3 éléments

* Obligatoire

🚂
Longueur des données
id, email, picture_url et website_url ne doivent pas dépasser la longueur maximale. Sinon, un message d'erreur s'affichera et l'embed ne se chargera pas. Si name, title, bio ou location dépasse la longueur maximale, la valeur sera tronquée.
🔐
Confidentialité des données
Les champs name, picture_url, website_url, bio et location seront affichés publiquement. L'email ne sera utilisé que pour envoyer des notifications par e-mail en cas de réponses et de mentions. Si vous ne souhaitez pas que nous envoyions de notifications par e-mail, définissez l' email sur une valeur factice (mais unique) comme [id]@votreentreprise.org. Désactivez ensuite les notifications par e-mail dans la console.
💡
Remarque : badge_ids
Vous pouvez utiliser le champ badge_ids pour gérer les badges associés à un utilisateur. Si vous fournissez un tableau, il remplacera les badges existants de l'utilisateur. Si vous fournissez un objet avec les clés add et remove, il modifiera les badges existants en conséquence. N'oubliez pas qu'un utilisateur peut avoir au maximum 3 badges à tout moment.
// Remplacer les badges existants de l'utilisateur
userData.badge_ids = [1, 2, 3];

// Modifier les badges existants de l'utilisateur
userData.badge_ids = {
	add: [2, 3],
	remove: [1]
};

Étape 3 : convertir l'objet en JSON puis en base64

Commencez par convertir l'objet utilisateur en chaîne JSON. Encodez-la ensuite en base64.

// 1. Encodage JSON
userData = JSON.stringify(userData);

// 2. Encodage Base64
userData = Buffer.from(userData).toString('base64');
Pourquoi l'encodage JSON et base64 ?
L'encodage JSON facilite la transmission des données, et la plupart des langages disposent de bibliothèques intégrées pour encoder/décoder le JSON. L'encodage base64 permet d'afficher ces données dans du code HTML. Globalement, l'encodage JSON et base64 est une question de commodité, pas de sécurité.

(l’encodage base64 est facultatif, mais recommandé)

Étape 4 : créer le hash HMAC

L'étape suivante consiste à générer un hash HMAC à partir de userData. Pour cela, nous avons besoin de la clé privée que vous avez reçue lors de la configuration du SSO sans état dans la console. Nous utilisons HMAC SHA 256.

Nous utilisons ici la bibliothèque JavaScript crypto-js. Cependant, la plupart des langages de programmation disposent de fonctions de hachage HMAC intégrées. Veillez à remplacer YOUR_PRIVATE_KEY par votre propre clé privée, disponible dans Console → Paramètres → Authentification unique.

const CryptoJS = require('crypto-js');
const hash = CryptoJS.HmacSHA256(userData, YOUR_PRIVATE_KEY);
Pourquoi le hash ?
Pour connecter le SSO de manière sécurisée, nous devons nous assurer que les données utilisateur SSO reçues ont été générées par vous, et non par quelqu'un d'autre. Le hash le garantit. Comme la clé privée n'est partagée qu'entre vous et nous, personne d'autre ne peut générer un hash HMAC valide. Ainsi, lorsque nous affichons les embeds, nous vérifions que les données utilisateur et le hash correspondent. Et c'est seulement alors que nous connectons l'utilisateur.
Pourquoi un timestamp dans l'objet utilisateur ?
Cette valeur nous permet de faire expirer les anciens objets. Notre système n'acceptera pas de timestamp datant de plus de 7 jours, ce qui laisse suffisamment de temps pour une session de navigateur, tout en limitant le risque d'attaques par rejeu. Nous recommandons de générer un nouveau hash avec un nouveau timestamp à chaque chargement de page. Ou, si vous avez une application monopage, à chaque chargement initial.

Voici le code complet en JS (Node) :

if (isUserLoggedIn()) {
	// voici l'utilisateur de votre système
	const user = getUser();

	// créer un objet que Hyvor Talk comprend
	let userData = {
		id: user.id,
		name: user.fullname,
		email: user.email,
		picture_url: user.picture,
		website_url: user.website
	};

	// 1. Encodage JSON
	userData = JSON.stringify(userData);

	// 2. Encodage Base64
	userData = Buffer.from(userData).toString('base64');

	// Hash HMAC SHA256
	const CryptoJS = require('crypto-js');
	const hash = CryptoJS.HmacSHA256(userData, YOUR_PRIVATE_KEY);

	return {
		user: userData, // attribut sso-user
		hash: hash.toString() // attribut sso-hash
	};
}

Étape 5 : définir les attributs

La dernière étape consiste à définir les attributs dans le composant :

  • sso-user avec la variable userData
  • sso-hash avec la variable hash

Consultez Initialisation synchrone ou asynchrone pour savoir comment définir ces attributs dans différents scénarios.

Considérations de sécurité

  • Conservez la clé privée en lieu sûr dans .env ou dans un coffre de clés. Ne la versionnez pas dans le contrôle de source.
  • En cas de compromission, vous devez régénérer la clé privée.
  • Si vous utilisez un point de terminaison d'API pour générer le hash, utilisez toujours la méthode HTTP POST, sans aucune mise en cache.
  • Si vous affichez les données directement dans le HTML, ne mettez jamais en cache les réponses HTML.

SSO sans état sans clé

Vous pouvez également configurer le SSO sans état sans le hash, mais lisez attentivement ce qui suit :

Avertissement de sécurité !

Le SSO sans état sans clé ne valide pas l'authenticité des données utilisateur. Cela signifie que si un ID utilisateur est compromis, un attaquant peut usurper l'identité de n'importe quel utilisateur. Cette option ne doit être utilisée que si :

  • Vous n'avez pas accès au backend de votre site web (par exemple, un site Webflow). Si vous y avez accès, vous devez utiliser le hash.
  • Les ID utilisateur sont sécurisés et aléatoires (ex. : UUID) et vous les gardez privés. Si vous avez des ID auto-incrémentés ou tout autre ID prévisible, vous devez utiliser le hash.

Si vous avez un fournisseur d'authentification qui prend en charge le protocole OpenID Connect, utilisez plutôt le SSO OpenID Connect.

Pour commencer, activez l'option Sans clé dans les paramètres SSO de la console. Ensuite, vous pouvez définir l'attribut sso-user avec une chaîne JSON. Voici un exemple :

const comments = document.querySelector('hyvor-talk-comments');

comments.setAttribute(
	'sso-user',
	JSON.stringify({
		timestamp: Math.floor(Date.now() / 1000),

		id: 'user-id',
		name: 'user-name',
		email: 'user-email',
		picture_url: 'user-picture-url',
		website_url: 'user-website-url'
	})
);

Consultez les propriétés de l'objet de données utilisateur pour connaître les propriétés que vous pouvez définir.