Skip to content

API de SSKS

L'URL par défaut de SSKS est ssks.seald.io pour l'environnement de production, et ssks.staging-0.seald.io pour l'environnement de tests.

En-têtes des requêtes

L'authentification se fait par des headers HTTP :

VariableTypeDescription
X-SEALD-APPID (requis)StringApplication ID, donné sur le tableau d'administration du Seald SDK
X-SEALD-APIKEY (requis)StringClé d'API, donnée sur le tableau d'administration du Seald SDK
Content-typeStringapplication/json

Pour savoir où trouver ces valeurs, référez-vous au paragraphe en question dans le guide concernant l'intégration du 2-man-rule.

Requêtes pour la protection par 2-man-rule

Envoi d'un challenge

Ce point d'API est appelé par le serveur de l'application utilisant le SDK, et permet de :

  • Créer un "utilisateur" au sens de SSKS (si create_user est à true) ;
  • Créer une "Session" ;
  • Si une identité a déjà été stockée sur SSKS avec ce auth_factor (adresse email ou numéro de téléphone, voir le paragraphe Vérification du must_authenticate pour les détails de la comparaison), ou si force_auth est mis à true, alors must_authenticate est mis à true ; si non, à false ;
  • Retourner un session_id et must_authenticate ;
  • Si must_authenticate est true, envoyer un challenge à l'utilisateur, par email ou SMS, le backend ne doit pas avoir accès à ce challenge. Le challenge est valable 6h.

Le backend doit renvoyer le session_id et must_authenticate au frontend, tel qu'expliqué dans le guide d'intégration du 2-man-rule sur le backend.

TIP

L'envoi de challenge par SMS est limité au quota de SMS autorisé pour votre team. Si le quota est dépassé, votre requête recevra une erreur 406 Not Acceptable: {"detail": "SMSQuotaFailed"}.

N'hésitez pas à nous contacter pour augmenter le quota de SMS de votre équipe.

URL

POST https://{SSKS_URL}/tmr/back/challenge_send/

Format du corps de la requête

Il s'agit d'une requête POST au format JSON :

VariableTypeDescription
create_user (default: false)BooleanSi true, créé un utilisateur s'il n'existe pas. Sinon rejette avec une erreur 404. Si inutilisé, l'application doit manuellement créer un utilisateur
user_id (requis)StringIdentifiant unique de l'utilisateur. Peut être un ID, un UUID, une adresse email. La donnée est stockée en clair sur SSKS.
auth_factor (requis)ObjectFacteur authentication de l'utilisateur. Utilisée pour envoyer le challenge. Peut être identique pour plusieurs utilisateurs tant que le user_id est unique.
auth_factor.type (requis)StringType de facteur d'authentification. "EM" pour une adresse email, "SMS" pour un numéro de téléphone.
auth_factor.value (requis)StringAdresse e-mail ou numéro de téléphone de l'utilisateur. Utilisé pour envoyer le challenge. Doit absolument être normalisé. La valeur n'est pas stockée en clair sur SSKS, consultez le paragraphe Stockage des facteurs d'authentification pour plus de détails.
email (deprecated)StringObsolète, utilisez auth_factor. Adresse e-mail de l'utilisateur.
force_auth (default: false)BooleanPermet de forcer l'envoi d'un challenge d'authentification, même si ce auth_factor n'a jamais été utilisé précédemment.
template (requis)StringTemplate au format HTML de l'email contenant le challenge d'authentification envoyé à l'utilisateur. Doit contenir le String $$CHALLENGE$$ qui sera remplacé par le challenge par SSKS.
subjectStringObjet de l'email envoyé avec le challenge. Défaut à "End-to-end encryption challenge". Ignoré pour le SMS.
fake_otp (default: false)BooleanUniquement en environnement de test / staging. Si true, n'enverra pas d'email ou SMS. Le challenge sera toujours aaaaaaaa. Si true en environnement de production, renverra une erreur 406.

TIP

En cas d'envoi de SMS à un numéro aux États-unis, une prévalidation du template peut être nécessaire.

N'hésitez pas à nous contacter pour mettre cela en place.

Format de la réponse

Au format JSON :

VariableTypeDescription
session_idStringID de la session ainsi créée. Doit être transmis au frontend.
must_authenticateBooleanBooléen indiquant si la session créée a besoin d'un challenge. Si true, le serveur envoie un email à l'utilisateur, contenant ce challenge, qu'il devra répéter dans le frontend dans les 6h. Si false, la session peut directement enregistrer son identité sur SSKS sans challenge.
task_idStringSi le challenge prend moins de 3 secondes pour être envoyé à l'utilisateur, ce champ sera None. Sinon, task_id sera un String à utiliser avec /tmr/back/check_task/ pour suivre l'état d'avancement de l'envoi.

Vérifier l'état d'une task_id

Ce point d'API peut être utilisé par le serveur lorsque l'envoi d'un challenge prend plus de 3 secondes.

Dans ce cas, /tmr/back/challenge_send/ devrait avoir retourné un task_id qui peut être utilisé sur ce point d'API.

TIP

Les tâches sont supprimées 24 heures après leur réussite. Dans ce cas, la vérification d'une ancienne tâche réussie peut ne pas renvoyer le statut SUCCESS.

URL

POST https://{SSKS_URL}/tmr/back/check_task/

Format du corps de la requête

Il s'agit d'une requête POST au format JSON :

VariableTypeDescription
task_idStringValeur de task_id donnée dans /tmr/back/challenge_send/.

Format de la réponse

Au format JSON :

VariableTypeDescription
statusStringSUCCESS lorsque le challenge est envoyé à l'utilisateur. FAILURE ou REVOKED lorsque l'envoi du challenge a échoué. Toute autre valeur lorsque la tâche n'a pas encore été exécutée.

Vérification du must_authenticate

Ce point d'API peut être utilisé par le serveur de l'application utilisant le SDK avant d'envoyer le challenge pour vérifier la valeur que prendrait must_authenticate si le point d'api d'envoi était appelé.

Cela permet de déterminer si une identité a déjà été stockée pour un auth_factor donné.

TIP

Pour décider de la valeur de must_authenticate, le serveur SSKS n'utilise pas simplement le facteur d'authentification brut donné par la requête pour vérifier si une identité a déjà été stocké avec celui-ci ou pas. Il essaye aussi d'enlever les alias potentiellement présents.

Par exemple, pour les adresses emails Gmail, ce qui suit le + est ignoré : email@gmail.com et email+alias@gmail.com sont considérés comme équivalents.

La procédure précise utilisée pour ce faire est susceptible d'être modifiée pour être améliorée.

URL

POST https://{SSKS_URL}/tmr/back/must_authenticate/

Format du corps de la requête

Il s'agit d'une requête POST au format JSON :

VariableTypeDescription
type (requis)String"EM" pour une adresse e-mail, "SMS"" pour un numéro de téléphone.
value (requis)StringAdresse e-mail ou numéro de téléphone de l'utilisateur. Doit absolument être normalisé.

Format de la réponse

Au format JSON :

VariableTypeDescription
must_authenticateBooleanBooléen indiquant si la session créée a besoin d'un challenge. Si true, le serveur devra envoyer un email à l'utilisateur au prochain send_challenge.

Création manuelle d'un utilisateur

Ce point d'API peut être utilisé si create_user est à False sur le point d'API précédent. Cela va juste créer un "utilisateur" vierge au sens de SSKS.

URL

POST https://{SSKS_URL}/tmr/back/create_user/

Format du corps de la requête

VariableTypeDescription
user_id (requis)StringIdentifiant unique de l'utilisateur. Peut être un ID, un UUID, une adresse email. La donnée est stockée en clair sur SSKS.
auth_factor (requis)Objectfacteur authentication de l'utilisateur. Utilisée pour envoyer le challenge.
auth_factor.type (requis)StringType de facteur d'authentification. 'EM' pour une adresse email, 'SMS' pour un numéro de téléphone.
auth_factor.value (requis)StringAdresse e-mail ou numéro de téléphone de l'utilisateur. Doit absolument être normalisé. La valeur n'est pas stockée en clair sur SSKS, consultez le paragraphe Stockage des facteurs d'authentification pour plus de détails.
email (deprecated)StringObsolète, utilisez auth_factor. Adresse e-mail de l'utilisateur.

Réponse

Ce point d'API n'a pas d'information à retourner au serveur. Il répond simplement avec {"status": "ok"}.

Suppression d'un utilisateur

Ce point d'API peut être utilisé pour supprimer toutes les données stockées sur un utilisateur sur SSKS.

URL

POST https://{SSKS_URL}/tmr/back/delete_user/

Format du corps de la requête

VariableTypeDescription
user_id (requis)StringIdentifiant unique qui avait été utilisé pour créer l'utilisateur à supprimer.
auth_factor (optionnel)ObjectObjet contenant les informations d'authentification d'un utilisateur. Si renseigné, uniquement l'utilisateur possédant ce auth_factor sera supprimé. (Cela peut être utile en cas de doublons d'user_id)
auth_factor.type (requis si auth_factor est utilisé)StringType de facteur d'authentification. 'EM' pour une adresse email, 'SMS' pour un numéro de téléphone.
auth_factor.value (requis si auth_factor est utilisé)StringAdresse e-mail ou numéro de téléphone de l'utilisateur. Doit absolument être normalisé.
full_forget (optionnel)BooleanUniquement en environnement de test / staging. Si true, supprime complètement l'utilisateur, pour éviter que must_authenticate soit true en cas de stockage d'une autre identité avec le même facteur. Si true en environnement de production, renverra une erreur 406.

Réponse

VariableTypeDescription
statusStringok si la requête s'est déroulée correctement
deletedNumberNombre d'identité supprimées

Vérification de l'existence d'une identité

Ce point d'API peut être utilisé pour vérifier si pour un user_id (éventuellement couplé avec un auth_factor) donné une identité protégée en 2-man-rule existe.

Il répond avec le nombre d'identités correspondant à cet utilisateur, soit 0 quand il n'y en a pas ou si l'utilisateur n'existe pas, soit un nombre strictement positif s'il y en a une ou plus.

Il est aussi possible de vérifier s'il y a une identité stockée pour un user_id sans vérifier le auth_factor auquel il est associé.

URL

POST https://{SSKS_URL}/tmr/back/identity_check/

Format du corps de la requête

VariableTypeDescription
user_id (requis)StringIdentifiant unique qui a été utilisé pour créer l'utilisateur à vérifier.
auth_factor (optionnel)ObjectFacteur authentication de l'utilisateur. Utilisée pour envoyer le challenge.
auth_factor.type (requis si auth_factor.value est donné)StringType de facteur d'authentification. 'EM' pour une adresse email, 'SMS' pour un numéro de téléphone.
auth_factor.value (requis si auth_factor.type est donné)StringAdresse e-mail ou numéro de téléphone de l'utilisateur. Doit absolument être normalisé.

Réponse

VariableTypeDescription
identities_countNumberNombre d'identités stockées pour ce user_id éventuellement filtré par auth_factor.
userObjectInformations sur l'utilisateur requêté
user.user_idObjectuser_id donné dans la requête
user.app_idObjectapp_id de l'application dans Seald

Récupération d'identités

Ce point d'API peut être utilisé pour récupérer des informations sur les identités stockées.

URL

GET https://{SSKS_URL}/tmr/back/identities/?user_id={user_id}&id={id}&cursor={cursor}

Format des paramètres requête

VariableTypeDescription
cursorStringEn cas de résultat nombreux, à utiliser pour avoir les résultats suivants ou précédents.
user_idStringIdentifiant unique qui avait été utilisé pour créer l'utilisateur.
idStringIdentifiant unique qui a été rendu à la création de l'identité.

Réponse

Ce point d'API renvoie de façon paginée les informations suivantes.

VariableTypeDescription
next_cursorStringValeur à utiliser dans cursor pour récupérer les résultats précédents.
previous_cursorStringValeur à utiliser dans cursor pour récupérer les résultats suivants.
resultsStringRésultats (cf. ci-dessous).

result est sous le format suivant :

VariableTypeDescription
idStringIdentifiant unique qui à été rendu à la création de l'identité.
app_idStringapp_id de l'application dans Seald.
createdStringDate de la création de l'identité.
user_idStringIdentifiant unique qui a été utilisé pour créer l'utilisateur.
auth_factor_typeStringType de facteur d'authentification. 'EM' pour une adresse email, 'SMS' pour un numéro de téléphone.
hash_convertedBooleanTrue si le hash du facteur d'authentification a été une première fois migré.
hash_v2_convertedBooleanTrue si le hash du facteur d'authentification a été une deuxième fois migré.

Suppression d'identité (2)

Ce point d'API peut être utilisé pour supprimer l'identité correspondant à un id, ou toutes les identitées stockées pour un user_id.

URL

DELETE https://{SSKS_URL}/tmr/back/identities/?user_id={user_id}&id={id}

Format des paramètres de la requête

VariableTypeDescription
user_id (requis*)StringIdentifiant unique qui avait été utilisé pour créer l'utilisateur à supprimer.
id (requis*)StringIdentifiant unique qui a été rendu à la création de l'identité.

* user_id ou id est requis, mais pas les deux. Un seul de ces deux paramètres est suffisant.

Réponse

Ce point d'API n'a pas d'information à retourner au serveur. Il répond simplement avec un {"status": "ok"}.

Normalisation des authFactors

Lors de l'utilisation de SSKS pour la protection en 2-man-rule, tous les authFactors envoyés à SSKS doivent être normalisés. Si un authFactor est envoyé de façon non-normalisée, le serveur SSKS pourra renvoyer une erreur.

WARNING

Pour l'instant, les authFactors non-normalisés sont encore acceptés, et sont normalisés en interne par le serveur.

Néanmoins, ils sont fortement déconseillés, et seront refusés d'ici quelques mois.

Normalisation des emails

Les adresses email sont normalisées en :

  • normalisant l'encodage du string en NFKC
  • enlevant les espaces
  • mettant la casse en minuscule

Pour effectuer cette normalisation, vous pouvez utiliser les snippets suivants :

  • en Python :
python
import unicodedata
normalized_email = unicodedata.normalize("NFKC", email).replace(" ", "").lower()
import unicodedata
normalized_email = unicodedata.normalize("NFKC", email).replace(" ", "").lower()
  • en JavaScript :
js
const normalizedEmail = email.normalize('NFKC').replace(/ /g, '').toLowerCase()
const normalizedEmail = email.normalize('NFKC').replace(/ /g, '').toLowerCase()

Normalisation des numéros de téléphone

Pour les numéros de téléphone, ceux-ci doivent absolument être envoyés au format standard international E.164.

Celui-ci correspond simplement au numéro de téléphone, sans aucun espace, précédé du code de pays noté avec un +.

Par exemple, les notations suivantes ne sont PAS valides :

  • 01 23 45 67 89
  • 0123456789
  • +33 1 23 45 67 89
  • +33-123456789
  • 0033123456789

Utilisez la notation suivante :

+33123456789

Pour convertir un numéro de téléphone quelconque au format E.164, des librairies existent dans différents langages. Par exemple, pour convertir un numéro en E.164 en considérant que nous sommes en France :

  • en Python, vous pouvez utiliser phonenumbers :
python
import phonenumbers
phonenumbers.format_number(phonenumbers.parse("01 23 45 67 89", "FR"), phonenumbers.PhoneNumberFormat.E164)
# '+33123456789'
import phonenumbers
phonenumbers.format_number(phonenumbers.parse("01 23 45 67 89", "FR"), phonenumbers.PhoneNumberFormat.E164)
# '+33123456789'
  • en JavaScript, vous pouvez utiliser google-libphonenumber :
js
import libPhoneNumber from 'google-libphonenumber'
const instance = libPhoneNumber.PhoneNumberUtil.getInstance()
instance.format(instance.parse('01 23 45 67 89', 'FR'), libPhoneNumber.PhoneNumberFormat.E164)
// '+33123456789'
import libPhoneNumber from 'google-libphonenumber'
const instance = libPhoneNumber.PhoneNumberUtil.getInstance()
instance.format(instance.parse('01 23 45 67 89', 'FR'), libPhoneNumber.PhoneNumberFormat.E164)
// '+33123456789'

Stockage des authFactors

La valeur des facteurs d'authentification n'est pas stockée en clair sur SSKS. Elle est d'abord normalisée, puis hachée. Le hash est stocké de manière à ce qu'il soit possible de vérifier que la valeur donnée est la même lorsqu'elle est utilisée ultérieurement.

De plus, une version désaliassée est calculée, puis hachée et stockée, afin que le SSKS puisse décider de la valeur de must_authenticate pour les demandes ultérieures.

Enfin, le auth_factor est également chiffré pour une clé que le serveur ne possède pas, et cette version chiffrée est stockée, afin que Seald soit en mesure, si nécessaire dans le futur, de migrer les procédures de hachage.

Migration

Au 31/01/2022, la fonction de hash a été mise à jour de la v1 à la v2 pour améliorer les performances en réduisant le nombre d'itérations de hash.

Au 01/01/2023, la fonction de hash a été mise à jour de la v2 à la v3 en introduisant une normalisation préalable, ainsi qu'un mécanisme de désaliassage afin de s'assurer qu'un changement de casse ou d'encodage du authFactor ne soit pas considéré comme un authFactor différent, et que l'utilisation d'alias courants d'emails ne permette pas de contourner une authentification.

Étant donné que la valeur des authFactor pour lesquels une identité chiffrée a été stockée en v1 ou en v2 n'est pas accessible par nos équipes, il nous est impossible de calculer le hash v3 pour ceux-ci. De ce fait, un mécanisme de migration lors de l'utilisation a été mis en œuvre :

Lors d'une requête contenant un authFactor (POST /tmr/back/challenge_send/, POST /tmr/back/must_authenticate/, POST /tmr/back/delete_user/, POST /tmr/back/identity_check/), SSKS calcule le hash v3, le hash v2 et le hash v1, puis :

  1. si le authFactor n'a pas de correspondance sur le hash v3, mais en a une sur le hash v1 ou v2, le authFactor est migré à un stockage en v3 et le vieux hash est supprimé.
  2. si le authFactor a une correspondance sur le hash v3 et a une correspondance sur le hash v1 ou v2, une collision liée à la normalisation est survenue qui notifie les équipes Seald et répond au client une erreur 500. Dans ce cas, il faut gérer la collision manuellement, veuillez nous contacter sur support@seald.io.
  3. sinon, le authFactor a une correspondance sur le hash v3, et pas sur le hash v1 et v2, ce qui est le fonctionnement normal.

DANGER

Il est crucial d'effectuer la migration avec la valeur brute, non-normalisée, des authFactor, telle qu'elle a été donnée lors du stockage de l'identité de l'utilisateur. En effet, dans le cas contraire, le serveur ne pourrait pas trouver la correspondance avec l'ancien hash v1 ou hash v2.

Une fois la migration de votre app terminée, il est recommandé de ne plus envoyé que la version normalisée des authFactor.

TIP

Une fois l'ensemble des utilisateurs d'une application migrés à une version de hash (v2 ou v3), les hashs de version antérieure ne sont plus calculés. En particulier, l'amélioration de performance du liée à l'introduction du hash v2 n'est effective qu'à partir du moment où l'ensemble des utilisateurs sont migrés au hash v2 au moins.

Effectuer la migration

Pour exécuter la migration sur l'ensemble des utilisateurs, vous devez :

  • Pour chaque utilisateur de votre application :
    • Pour chaque authFactor de cet utilisateur :
      • Faire un appel authentifié à POST /tmr/back/must_authenticate/ avec les paramètres { "type": <"EM"|"SMS">, "value": <value> }. Attention: il faut envoyer la valeur brute, non-normalisée, du authFactor telle qu'elle a été donnée lors du stockage de l'identité de l'utilisateur pour que la migration fonctionne.

Une fois effectuée, l'ensemble des utilisateurs connus dans votre application ont été migrés.

Il se peut que vous ayez d'autres identités inutilisées dans votre application qu'il faudrait supprimer. Pour confirmer que votre migration est bien terminée, veuillez nous contacter sur support@seald.io.

Une fois que vous avez confirmé auprès de Seald que l'ensemble des utilisateurs ont été migrés, vous pouvez normaliser les authFactor enregistrés dans votre application.

Requêtes pour la protection par mot de passe

Vérification de l'existence d'une identité

Ce point d'API peut être utilisé pour vérifier si un user_id donné a une ou plusieurs identités qui sont stockées protégées par mot de passe.

Il répond avec le nombre d'identités correspondant à cet utilisateur, soit 0 quand il n'y en a pas, soit un nombre strictement positif s'il y en a.

URL

POST https://{SSKS_URL}/strict/back/identity_check/

Format du corps de la requête

VariableTypeDescription
user_id (requis)StringIdentifiant unique qui a été utilisé pour créer l'utilisateur à vérifier.

Réponse

VariableTypeDescription
identities_countNumberNombre d'identités stockées pour ce user_id.
userObjectInformations sur l'utilisateur requêté
user.user_idObjectuser_id donné dans la requête
user.app_idObjectapp_id de l'application dans Seald

Suppression d'identité

Ce point d'API peut être utilisé pour supprimer toutes les identités stockées pour le compte d'un user_id.

Il n'est pas possible de distinguer plusieurs identités d'un même utilisateur. On ne peut donc que les supprimer conjointement.

URL

POST https://{SSKS_URL}/strict/back/identity_delete/

Format du corps de la requête

VariableTypeDescription
user_id (requis)StringIdentifiant unique qui avait été utilisé pour créer l'utilisateur à supprimer.

Réponse

Ce point d'API n'a pas d'information à retourner au serveur. Il répond simplement avec {"status": "ok"}.

Récupération d'identités

Ce point d'API peut être utilisé pour récupérer des informations sur les identités stockées.

URL

GET https://{SSKS_URL}/strict/back/identities/?user_id={user_id}&id={id}&cursor={cursor}

Format des paramètres requête

VariableTypeDescription
cursorStringEn cas de résultat nombreux, à utiliser pour avoir les résultats suivants ou précédents.
user_idStringIdentifiant unique qui avait été utilisé pour créer l'utilisateur.
idStringIdentifiant unique qui a été rendu à la création de l'identité.

Réponse

Ce point d'API renvoie de façon paginée les informations suivantes.

VariableTypeDescription
next_cursorStringValeur à utiliser dans cursor pour récupérer les résultats précédents.
previous_cursorStringValeur à utiliser dans cursor pour récupérer les résultats suivants.
resultsStringRésultats (cf. ci-dessous).

result est sous le format suivant :

VariableTypeDescription
idStringIdentifiant unique qui à été rendu à la création de l'identité.
app_idStringapp_id de l'application dans Seald.
createdStringDate de la création de l'identité.
user_idStringIdentifiant unique qui a été utilisé pour créer l'utilisateur.

Suppression d'identité (2)

Ce point d'API peut être utilisé pour supprimer l'identité correspondant à un id, ou toutes les identitées stockées pour un user_id.

URL

DELETE https://{SSKS_URL}/strict/back/identities/?user_id={user_id}&id={id}

Format des paramètres de la requête

VariableTypeDescription
user_id (requis*)StringIdentifiant unique qui avait été utilisé pour créer l'utilisateur à supprimer.
id (requis*)StringIdentifiant unique qui a été rendu à la création de l'identité.

* user_id ou id est requis, mais pas les deux. Un seul de ces deux paramètres est suffisant.

Réponse

Ce point d'API n'a pas d'information à retourner au serveur. Il répond simplement avec {"status": "ok"}.