Aller au contenu principal
Suivez les étapes suivantes pour configurer un webhook et commencer à envoyer des données en temps réel.

Déployer votre premier Webhook

1. Créer un endpoint pour vos Webhooks

Une fois que vous connaissez vos besoins, vous pouvez créer un endpoint qui servira de récepteur pour vos Webhooks. Nous enverrons les événements à cet endpoint en utilisant l'URL HTTP(S) que vous aurez fournie lors de la création de vos Webhooks. Un exemple simple d'endpoint en Ruby pourrait ressembler à ceci :

webhook-server.rb
require 'sinatra'
require 'json'

post '/webhook' do
puts request.body.read
end

Cet exemple a été créé à l'aide de la bibliothèque Sinatra. Ici, nous créons une route /webhook qui écoutera les requêtes HTTP POST.

2. Traiter les événements reçus

L'endpoint créé précédemment doit pouvoir récupérer les événements envoyés, les traiter et renvoyer une réponse 2xx.

Une fois les événements envoyés par Cryptr, nos services attendent une réponse. Si la réponse est une réponse 2xx, nous supposons que vous avez reçu l'événement et nous n'essaierons pas de l'envoyer à nouveau.

Si, en revanche, vous nous envoyez une réponse différente, nous essaierons de vous renvoyer les événements à certains intervalles de temps. Pour en savoir plus sur les différentes réponses que vous pouvez nous envoyer et leurs actions, vous pouvez consulter notre section Comment bien gérer vos webhooks qui traite de ce sujet.

Example of received event
{
"__domain__": "3-belges",
"__environment__": "sandbox",
"__type__": "Event",
"code": "dir_sync.user.update.success",
"data": {
"__type__": "DirectorySyncEvent",
"change": "update",
"directory_sync_id": "2cbd4ad8-1f3c-4ea0-84b6-691d4d469e57",
"provider": "okta",
"resource": {
"changes": {
"new_values": {
"address": {
"country": "FR",
"formatted": "12 rue des freres lumières\n68200 Mulhouse, France",
"locality": "Mulhouse",
"postal_code": "68200",
"region": "Alsace",
"street_address": "12 rue des freres lumières"
},
"phone_numbers": [
{
"default": false,
"phone_country_code": 33,
"phone_national_number": "345676543",
"primary": true,
"type": "mobile",
"value": "+33345676543"
},
{
"default": true,
"phone_country_code": 33,
"phone_national_number": "687435543",
"primary": true,
"type": "work",
"value": "+33687435543"
}
],
"profile": {
"family_name": "O'neil",
"given_name": "April",
"preferred_username": "April O'neil",
},
"updated_at": "2023-06-06T08:49:33"
},
"previous_values": {
"address": {
"country": null,
"formatted": "12 rue des freres lumières\nMulhouse",
"locality": "Mulhouse",
"postal_code": null,
"region": null,
"street_address": "12 rue des freres lumières"
},
"phone_numbers": [],
"profile": {
"family_name": null,
"given_name": "Aprils",
"preferred_username": "O'neil",
},
"updated_at": "2023-06-06T08:06:21"
}
},
"id": "b4702922-5868-4db8-bcd9-87ab40af50ed",
"type": "User"
}
},
"errors": null,
"params": {
"addresses": [
{
"country": "FR",
"locality": "Mulhouse",
"postalCode": "68200",
"region": "Alsace",
"streetAddress": "12 rue des freres lumières"
}
],
"phoneNumbers": [
{
"primary": true,
"type": "work",
"value": "+33345676543"
},
{
"primary": true,
"type": "mbile",
"value": "+33687435543"
}
],
"name": {
"familyName": "O'neil",
"givenName": "April"
},
"displayName": "April O'neil",
},
"issued_at": "2023-06-06T08:49:33.075265Z",
"webhook_id": "webhook_2QauvX3scYnpadurUTdjrd59QrE"
}

Réponse

Pour que nous recevions votre réponse dans les plus brefs délais, vous devez envoyer une réponse dès que possible. Vous devez d'abord traiter l'envoi de la réponse avant tout autre traitement.

Retries

Tous les codes 3xx, 4xx et 5xx seront traités par Cryptr pour vous envoyer à nouveau un événement à différents intervalles que vous pouvez consulter dans notre section comment bien gérer un Webhook. Si nous ne recevons pas de réponse ou si nous ne la recevons pas à temps, nous supposerons que votre point de terminaison n'existe pas et nous n'enverrons pas l'événement à nouveau.

3. Créer un webhook de test

Pour utiliser les Webhooks, vous devez en créer un à l'aide de l'API ou de votre tableau de bord Cryptr. Voici la page Webhook où vous pouvez créer un Webhook rapidement :

Cryptr Dashboard - Create a Webhook

Ce Webhook écoutera tous les événements de synchronisation de répertoire. Si vous le souhaitez, vous pouvez modifier les codes d'événements à écouter en changeant la valeur de la clé event_codes (actuellement disponible uniquement par API). Pour obtenir une liste complète des event_codes disponibles, vous pouvez consulter notre section Liste des événements.

4. Tester la bonne réception des événements

Vérifiez que votre Webhook fonctionne correctement. Les événements sont-ils bien reçus ?

Maintenant que votre Webhook est créé, vous pouvez tester un événement correspondant à un événement écouté par votre Webhook. Dans le cas d'un Webhook qui écoute les événements Directory Sync, vous pouvez par exemple tester l'événement dir_sync.user.provision.success.

Pour ce faire, nous vous fournissons un point d'API pour déclencher l'envoi de faux événements. Pour en savoir plus, voir Comment tester un Webhook ou notre documentation API.

Si vous avez utilisé le même endpoint que dans notre exemple de l'étape 2, vous devriez voir le corps de la requête POST que nous vous avons envoyée dans votre terminal.

5. Déployez vos points d'extrémité sur vos services

Si les tests sont concluants, déployez votre endpoint Webhook dans vos services de production.

Une fois la configuration testée, vous pouvez répéter les étapes précédentes dans votre environnement de production. Il est possible de créer plusieurs webhooks différents qui écoutent plusieurs événements différents, mais aussi de définir des endpoints cibles différents pour chacun de vos webhooks. Par exemple, un Webhook qui envoie des événements SCIM à un Endpoint /scim-webhook et un autre qui envoie des événements SSO à un Endpoint /sso-webhook.

Comment gérer correctement vos Webhooks

Il est important de bien gérer vos Webhooks. Pour cela, quelques conseils et informations peuvent vous être utiles.

Sélectionnez les événements que vous souhaitez recevoir​

La première chose à faire est de sélectionner judicieusement les événements reçus. Réfléchissez bien aux événements qui vous importent vraiment. En effet, avoir un Webhooks qui gère tous les événements peut être tentant mais cela pourrait rapidement surcharger votre Endpoint et rendre la lecture compliquée. C'est pourquoi il est préférable de privilégier la qualité à la quantité en se limitant aux événements dont vous avez réellement besoin.

Par exemple, si j'ai besoin de savoir quand un utilisateur est créé par SCIM, je dois écouter l'événement dir_sync.user.provision.success.

Les différents codes d'état que vous pouvez renvoyer​

La première chose à faire lorsque vous recevez un événement est bien sûr de nous envoyer une réponse avec un code 2xx. Mais vous pouvez aussi utiliser d'autres codes qui seront pris en compte différemment chez Cryptr.

Codes 2xx

Tous les codes entre 199 et 300 non inclus sont des codes signifiant un envoi réussi. Cryptr interprétera alors ces réponses comme telles et supposera que vous avez reçu l'événement.

410 Code

Le code 410 est utilisé pour nous informer que vous souhaitez annuler l'envoi d'un événement. Si vous nous envoyez un code 410, nous cesserons de vous envoyer cet événement.

4xx codes

Pour tous les autres codes 4xx, Cryptr tentera de vous renvoyer l'événement à différents intervalles, comme suit :

Tentative initial0
Tentative #15 minutes
Tentative #210 minutes
Tentative #320 minutes
Tentative #41 hour
Tentative #42 hours


503 retry-after

Cette option, qui peut être incluse dans l'en-tête HTTP de la réponse que vous nous envoyez, vous permet de définir vous-même une durée après laquelle nous réessayerons de vous envoyer l'événement. Pour ce faire, il suffit de nous envoyer un code de réponse 503 et d'inclure dans l'en-tête http de votre réponse HTTP la clé retry-after suivie d'une valeur en secondes. En voici un exemple :

{“retry-after”, 60}

Cela redémarre l'envoi d'un événement à votre point de terminaison après 60 secondes.

Liste des événements​

info

Si vous souhaitez recevoir tous les événements Directory Sync, il vous suffit d'indiquer dir_sync.all dans la clé event_codes au lieu de la liste des codes d'événements.

Codes des événements de synchronisation de l'annuaire

ÉvénementEvent_Code
Directory Sync activédir_sync.activate.success
Directory Sync désactivédir_sync.deactivate.success
Utilisateur crée via Directory Syncdir_sync.user.provision.success
Utilisateur mis à jour via Directory Syncdir_sync.user.update.success
Utilisateur supprimé via Directory Syncdir_sync.user.deprovision.success
Utilisateur creation via Directory Sync échouédir_sync.user.provision.fail
Utilisateur update via Directory Sync échouédir_sync.user.update.fail
Utilisateur deletion via Directory Sync échouédir_sync.user.deprovision.fail
Groupe crée via Directory Syncdir_sync.group.provision.success
Groupe mis à jour via Directory Syncdir_sync.group.update.success
Groupe supprimé via Directory Syncdir_sync.group.deprovision.success
Création d'un Groupe via Directory Sync échouédir_sync.group.provision.fail
Mise à jour d'un Groupe via Directory Sync échouédir_sync.group.update.fail
Suppression d'un Groupe via Directory Sync échouédir_sync.group.deprovision.fail
Utilisateur activé via Directory Syncdir_sync.user.activate.success
Utilisateur désactivé via Directory Syncdir_sync.user.deactivate.success
Activation d'un Utilisateur via Directory Sync échouédir_sync.user.activate.fail
Désactivation d'un Utilisateur via Directory Sync échouédir_sync.user.deactivate.fail
Groupe activé via Directory Syncdir_sync.group.activate.success
Groupe désactivé via Directory Syncdir_sync.group.deactivate.success
Activation d'un Groupe via Directory Sync échouédir_sync.group.activate.fail
Désactivation d'un Groupe via Directory Sync échouédir_sync.group.deactivate.fail

Sécurité des Webhooks

Chaque événement envoyé par Cryptr à votre (vos) endpoint(s) contient une signature. La sécurité est un concept important, c'est pourquoi cette signature a été ajoutée. Vous pouvez l'ignorer si vous le souhaitez, mais il n'est pas recommandé de le faire. En effet, cette clé vous permettra de vérifier que les événements reçus ont bien été envoyés par Cryptr et non par une personne extérieure.

1. Obtenir les données nécessaires

Obtenir la clé de signature Cryptr

La signature Cryptr est située dans l'en-tête de la requête HTTP sous la clé cryptr-signature. En effet, lorsque vous recevez une requête ou une réponse HTTP, le payload est constituée d'informations du protocole HTTP, telles que des en-têtes, une URL, le contenu du corps, la version et les informations d'état.

Voici à quoi ressemble un en-tête HTTP :

Header
Content-Type: application/json; charset=UTF-8
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0
cryptr-signature: t=1676905124,v1=sha256.640e3f227fed2123e84101cc69f41fba3435ec3b8f28d4ea249231f928efa990,v0=sha256.3d5990d850a7bbe430bf6ed93329f5b61b3fb72871afed9a071f3b95317d73ab

Par exemple, vous pouvez récupérer la cryptr-signature en exécutant la fonction suivante :

ruby
cryptrSignature = request.env["HTTP_CRYPTR_SIGNATURE"]

Voici un exemple de signature Cryptr :

cryptr-signature: t=1676905124,v1=640e3f227fed2123e84101cc69f41fba3435ec3b8f28d4ea249231f928efa990,v0=3d5990d850a7bbe430bf6ed93329f5b61b3fb72871afed9a071f3b95317d73ab

Récupérer l'horodatage

Chaque cryptr-signature contient un timestamp. Cet horodatage, que vous devrez récupérer et utiliser, empêche les attaques par rejeu.

Vous pouvez procéder comme suit pour récupérer l'horodatage :

ruby
# Split the cryptr-signature
array = cryptrSignature.split

# Get the timestamp from the splitted signature
timestamp = array.first

Extraire la signature

Chaque cryptr-signature contient également une signature v1. Mais il peut aussi contenir une signature v0 si votre secret a été mis à jour.

La signature v1 est la signature la plus récente, la signature v0 est la signature réalisée avec la signature_key précédente. Ceci a été pensé pour que vous ayez le temps de faire les changements nécessaires sans être bloqué si la signature_key change. Bien que les deux versions soient utilisables, il est fortement recommandé de n'utiliser que v1 dans la mesure du possible.

Pour récupérer vos signatures, procédez comme suit :

ruby
# Split the cryptr-signature
array = cryptrSignature.split

# Get the Signature V1 from the splitted signature
signatureV1 = array[1]
# Get only the necessary data
signatureV1.slice! "sha256."

# OPTIONAL: Get the Signature V0 from splitted signature
# signatureV0 = array[2]
# Get only the necessary data
# signatureV0.slice! "sha256."
info

Notez que nous ne prenons pas la valeur brute de la signature, mais seulement ce qui vient après le sha256..

⚠️ N'oubliez pas le . .

Une fois cela fait, nous pouvons passer à l'étape suivante.

2. Récupérez votre clé secrète

Pour vérifier vos signatures, vous devez récupérer la signature_key des webhooks dont vous voulez garantir l'authenticité. Si vous ne vous en souvenez pas, vous pouvez toujours la récupérer via la requête suivante :

cURL
curl 'https://${cryptr_service_url}/api/v2/webhooks/${webhook_id}'

Vous obtiendrez le résultat suivant :

Webhook Payload
{
"__environment__": "production",
"__type__": "Webhook",
"active": true,
"event_codes": ["dir_sync.user.provision.success"],
"id": "41f555de-6dac-4f24-8d0a-dc3499497ef0",
"inserted_at": "2023-11-07T15:31:30",
"name": "SCIM Webhook",
"signature_key": "0Zrk1pQnc10hh5ZDecqQfMDKy0S2FfdWU7ZJQ40Mh2TgweRcXM5Um3b6P0aUkFqf",
"target_url": "https://cryptr.site/webhook",
"updated_at": "2023-11-07T15:31:30"
}

Chaque webhook que vous créez aura une signature_key différente. Même si vous créez des webhooks avec des paramètres presque identiques ou si vous avez deux webhooks identiques dans l'environnement de production et dans l'environnement sandbox, ces derniers auront des clés différentes ; assurez-vous donc que la clé que vous allez utiliser est la clé correspondante.

Une fois que vous avez le timestamp, la Signature Cryptr v1 (ou v0) et la signature_key, vous pouvez passer à l'étape suivante.

3. Signer l'événement que vous avez reçu

Récupérer l'événement à signer

Désormais, chaque fois que vous recevrez un événement, vous disposerez de toutes les informations nécessaires. Pour commencer, voici à quoi ressemble la charge utile d'un événement :

Example of an event received
{
"__domain__": "shark-academy",
"__environment__": "sandbox",
"__type__": "Event",
"code": "dir_sync.user.update.success",
"data": {
"__domain__": "synchronizable",
"__type__": "DirectorySyncEvent",
"change": "update",
"directory_sync_id": "6aefc945-0815-4631-8ded-edc7bb1944ae",
"provider": "okta",
"resource": {
"changes": {
"new_values": {
"active": true,
"updated_at": "2023-10-17T08:12:37"
},
"previous_values": {
"active": false,
"updated_at": "2023-10-17T08:11:38"
}
},
"id": "7e2f977c-a8f0-4451-8967-fe63b243e7a1",
"type": "User"
}
},
"errors": null,
"issued_at": "2023-10-17T08:12:38.113207Z",
"params": {"active": true, "id": "7e2f977c-a8f0-4451-8967-fe63b243e7a1"},
"webhook_id": "webhook_2Wsnp8azBTeK2r29TExX9vBvnCg"
}
remarque

Vous pouvez utiliser l'identifiant webhook_id contenu dans ce payload pour vous aider à récupérer les informations correctes à l'étape B.

Préparer la chaîne à signer

Pour créer la chaîne à signer, il faut ensuite concaténer plusieurs éléments, les éléments à concaténer sont les suivants :

  • L'horodatage (sous forme d'une chaîne)
  • Le caractère .
  • La forme Stringifié du payload JSON (le contenu de la requête reçu)

Ce qui donnerait quelque chose comme ceci :

Ruby
require 'json'

stringifiedPayload = JSON.generate(payload)
stringToSign = timestamp + "." + stringifiedPayload
# => "1676905124.{\"__domain__\":\"shark-academy\",\"__environment__\":\"sandbox\",\"__type__\":\"Event\",...}"

Nous devons maintenant signer cette chaîne.

Signer la chaîne résultante

Pour signer la chaîne obtenue précédemment, utilisez la fonction de hachage SHA256 avec la signature_key associée à votre webhook comme secret. Vous obtiendrez ainsi un HMAC que vous pourrez comparer aux valeurs de signatureV1 ou de signatureV0 obtenues à l'étape A.3.

Ruby
# Create a digest for the SHA256 Algorithm
digest = OpenSSL::Digest.new('sha256')

# Generate the HMAC of your previously constructed string using your Webhook signature_key
hmac = OpenSSL::HMAC.digest(digest, signature_key, stringToSign)

# Encode the Result in Base64 with no padding /!\
yourSignature = Base64.urlsafe_encode64(hmac, false)
attention

Assurez-vous que:

  • vous utilisez l'algorithme SHA 256
  • Votre charge utile n'a pas été réécrite (c'est-à-dire que l'ordre des clés est le même que lorsque vous l'avez reçue).
  • Vous avez désactivé le padding
  • Vous avez stringifié votre charge utile

4. Comparer la signature obtenue avec la signature fournie

Maintenant que vous avez établi la signature de la charge utile reçue, vous pouvez la comparer à celle envoyée par Cryptr.

Ruby
# Compare the Signature sent by Cryptr with yours
if yourSignature == signatureV1
# You can proceed
else
# Signatures are not equal
end

Si les deux signatures sont similaires, vous pouvez supposer que la charge utile que vous avez reçue a été envoyée par Cryptr.

Si vous recevez une signature correcte, vérifiez la date et l'heure auxquelles elle a été délivrée. Si la date est trop éloignée, vous pouvez la refuser.

Exemple complet

Voici un exemple complet:

Ruby
require 'json'
## STEP 1.Get the necessary data ##

# Get the Cryptr Signature Key
cryptrSignature = request.env["HTTP_CRYPTR_SIGNATURE"]

# Extract the timestamp
array = cryptrSignature.split
timestamp = array.first

# Extract the signature
signatureV1 = array[1]
signatureV1.slice! "sha256."

# OPTIONAL: Get the Signature V0 from splitted signature
# signatureV0 = array[2]
# signatureV0.slice! "sha256."

## STEP 2. Use your key

# See "Retrieve your Secret Key before" part

## STEP 3. Sign your data

payload = request.body.read

# Prepare the string to sign
stringifiedPayload = JSON.generate(payload)
stringToSign = timestamp + "." + stringifiedPayload

# Sign the result
digest = OpenSSL::Digest.new('sha256')
hmac = OpenSSL::HMAC.digest(digest, signature_key, stringToSign)
yourSignature = Base64.urlsafe_encode64(hmac, false)

## STEP 4. Compare the signature ##
if yourSignature == signatureV1
# You can proceed
else
# Signatures are not equal
end

Comment tester un Webhook

Pour déclencher un événement, vous pouvez utiliser notre déclencheur d'événement Webhook. Pour cela, vous pouvez utiliser la requête suivante :

cURL
curl -X POST '${cryptr_service_url}/api/v2/webhook-events/trigger-test' \
-d 'event_code=dir_sync.user.provision.success'

Erreurs Webhook

Lors de la synchronisation, il peut arriver qu'un utilisateur ne puisse pas être créé ou mis à jour. Dans ce cas, le champ errors peut vous aider.

Par exemple, il apparaîtra comme suit :

Errors example
  "errors": {
"phone_numbers": {
"data": [
{
"type": "work",
"value": "+00000",
"primary": true,
"phone_country_code": null,
"phone_national_number": null
}
],
"error": [
{
"value": [
"Invalid country calling code"
]
}
]
}
}

Les données reçues sont indiquées dans la première map phone_numbers, mais celles-ci posent problèmes.

La seconde map error est la raison de l'erreur.

Voici une liste d'erreurs possibles que vous pouvez rencontrer dans votre payload d'événement :

ErreurSignification
Invalid country calling codeLe code pays du numéro de téléphone n'a pas été reconnu.
invalid_formatLes données fournies pour le champ ne sont pas valides. (Int au lieu de float, email sans @...)
has already been takenLa valeur a déjà été prise pour ce champ et l'unicité est requise..
The string supplied did not seem to be a phone numberLe numéro de téléphone fourni n'est pas valide (le plus souvent, il s'agit d'un numéro vide).