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 :
Variable | Type | Description |
---|---|---|
X-SEALD-APPID (requis) | String | Application ID, donné sur le tableau d'administration du Seald SDK |
X-SEALD-APIKEY (requis) | String | Clé d'API, donnée sur le tableau d'administration du Seald SDK |
Content-type | String | application/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 dumust_authenticate
pour les détails de la comparaison), ou siforce_auth
est mis àtrue
, alorsmust_authenticate
est mis àtrue
; si non, àfalse
; - Retourner un
session_id
etmust_authenticate
; - Si
must_authenticate
esttrue
, envoyer unchallenge
à l'utilisateur, par email ou SMS, le backend ne doit pas avoir accès à cechallenge
. Lechallenge
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
:
Variable | Type | Description |
---|---|---|
create_user (default: false) | Boolean | Si 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) | String | Identifiant 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) | Object | Facteur 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) | String | Type de facteur d'authentification. "EM" pour une adresse email, "SMS" pour un numéro de téléphone. |
auth_factor.value (requis) | String | Adresse 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) | String | Obsolète, utilisez auth_factor . Adresse e-mail de l'utilisateur. |
force_auth (default: false) | Boolean | Permet de forcer l'envoi d'un challenge d'authentification, même si ce auth_factor n'a jamais été utilisé précédemment. |
template_id | String | ID du modèle à utiliser pour envoyer le challenge d'authentification à l'utilisateur. Les modèles sont à définir sur votre tableau d'administration |
template_extra_params | Object | Arguments supplémentaires à rajouter pour le modèle. Doit être un objet au format { "ARG_NAME": "Arg Value" } , contenant au maximum 10 arguments. Les noms d'arguments ne peuvent contenir que des lettres majuscules, des chiffres, et des tirets bas (A-Z0-9_ ), limité à une longueur de 32 caractères. Les valeurs d'arguments sont limités à une longueur de 256 caractères. Peut être utilisé par exemple pour ajouter le nom de l'utilisateur. |
template (deprecated) | String | Obsolète, utilisez template_id . Modèle contenant le challenge d'authentification envoyé à l'utilisateur. Pour un email, doit être au format HTML. Doit contenir le String $$CHALLENGE$$ qui sera remplacé par le challenge par SSKS. |
text_template (deprecated) | String | Obsolète, utilisez template_id . Pour email uniquement. Modèle au format texte de l'email contenant le challenge d'authentification envoyé à l'utilisateur. Doit contenir le String $$CHALLENGE$$ qui sera remplacé par le challenge par SSKS. |
subject (deprecated) | String | Obsolète, utilisez template_id . Pour email uniquement. Objet de l'email envoyé avec le challenge. Défaut à "End-to-end encryption challenge" . Ignoré pour le SMS. |
fake_otp (default: false) | Boolean | Uniquement 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 modèle peut être nécessaire.
N'hésitez pas à nous contacter pour mettre cela en place.
Format de la réponse
Au format JSON
:
Variable | Type | Description |
---|---|---|
session_id | String | ID de la session ainsi créée. Doit être transmis au frontend. |
must_authenticate | Boolean | Boolé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_id | String | Si 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
:
Variable | Type | Description |
---|---|---|
task_id | String | Valeur de task_id donnée dans /tmr/back/challenge_send/ . |
Format de la réponse
Au format JSON
:
Variable | Type | Description |
---|---|---|
status | String | SUCCESS 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
:
Variable | Type | Description |
---|---|---|
type (requis) | String | "EM" pour une adresse e-mail, "SMS"" pour un numéro de téléphone. |
value (requis) | String | Adresse e-mail ou numéro de téléphone de l'utilisateur. Doit absolument être normalisé. |
Format de la réponse
Au format JSON
:
Variable | Type | Description |
---|---|---|
must_authenticate | Boolean | Boolé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
Variable | Type | Description |
---|---|---|
user_id (requis) | String | Identifiant 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) | Object | facteur authentication de l'utilisateur. Utilisée pour envoyer le challenge . |
auth_factor.type (requis) | String | Type de facteur d'authentification. 'EM' pour une adresse email, 'SMS' pour un numéro de téléphone. |
auth_factor.value (requis) | String | Adresse 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) | String | Obsolè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
Variable | Type | Description |
---|---|---|
user_id (requis) | String | Identifiant unique qui avait été utilisé pour créer l'utilisateur à supprimer. |
auth_factor (optionnel) | Object | Objet 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é) | String | Type 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é) | String | Adresse e-mail ou numéro de téléphone de l'utilisateur. Doit absolument être normalisé. |
full_forget (optionnel) | Boolean | Uniquement 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
Variable | Type | Description |
---|---|---|
status | String | ok si la requête s'est déroulée correctement |
deleted | Number | Nombre 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
Variable | Type | Description |
---|---|---|
user_id (requis) | String | Identifiant unique qui a été utilisé pour créer l'utilisateur à vérifier. |
auth_factor (optionnel) | Object | Facteur authentication de l'utilisateur. Utilisée pour envoyer le challenge . |
auth_factor.type (requis si auth_factor.value est donné) | String | Type 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é) | String | Adresse e-mail ou numéro de téléphone de l'utilisateur. Doit absolument être normalisé. |
Réponse
Variable | Type | Description |
---|---|---|
identities_count | Number | Nombre d'identités stockées pour ce user_id éventuellement filtré par auth_factor . |
user | Object | Informations sur l'utilisateur requêté |
user.user_id | Object | user_id donné dans la requête |
user.app_id | Object | app_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
Variable | Type | Description |
---|---|---|
cursor | String | En cas de résultat nombreux, à utiliser pour avoir les résultats suivants ou précédents. |
user_id | String | Identifiant unique qui avait été utilisé pour créer l'utilisateur. |
id | String | Identifiant 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.
Variable | Type | Description |
---|---|---|
next_cursor | String | Valeur à utiliser dans cursor pour récupérer les résultats précédents. |
previous_cursor | String | Valeur à utiliser dans cursor pour récupérer les résultats suivants. |
results | String | Résultats (cf. ci-dessous). |
result
est sous le format suivant :
Variable | Type | Description |
---|---|---|
id | String | Identifiant unique qui à été rendu à la création de l'identité. |
app_id | String | app_id de l'application dans Seald. |
created | String | Date de la création de l'identité. |
user_id | String | Identifiant unique qui a été utilisé pour créer l'utilisateur. |
auth_factor_type | String | Type de facteur d'authentification. 'EM' pour une adresse email, 'SMS' pour un numéro de téléphone. |
hash_converted | Boolean | True si le hash du facteur d'authentification a été une première fois migré. |
hash_v2_converted | Boolean | True 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
Variable | Type | Description |
---|---|---|
user_id (requis*) | String | Identifiant unique qui avait été utilisé pour créer l'utilisateur à supprimer. |
id (requis*) | String | Identifiant 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 authFactor
s 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 authFactor
s 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 :
import unicodedata
normalized_email = unicodedata.normalize("NFKC", email).replace(" ", "").lower()
- en JavaScript :
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
:
import phonenumbers
phonenumbers.format_number(phonenumbers.parse("01 23 45 67 89", "FR"), phonenumbers.PhoneNumberFormat.E164)
# '+33123456789'
- en JavaScript, vous pouvez utiliser
google-libphonenumber
:
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 :
- 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é. - 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. - 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, duauthFactor
telle qu'elle a été donnée lors du stockage de l'identité de l'utilisateur pour que la migration fonctionne.
- Faire un appel authentifié à
- Pour chaque
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
Variable | Type | Description |
---|---|---|
user_id (requis) | String | Identifiant unique qui a été utilisé pour créer l'utilisateur à vérifier. |
Réponse
Variable | Type | Description |
---|---|---|
identities_count | Number | Nombre d'identités stockées pour ce user_id . |
user | Object | Informations sur l'utilisateur requêté |
user.user_id | Object | user_id donné dans la requête |
user.app_id | Object | app_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
Variable | Type | Description |
---|---|---|
user_id (requis) | String | Identifiant 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
Variable | Type | Description |
---|---|---|
cursor | String | En cas de résultat nombreux, à utiliser pour avoir les résultats suivants ou précédents. |
user_id | String | Identifiant unique qui avait été utilisé pour créer l'utilisateur. |
id | String | Identifiant 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.
Variable | Type | Description |
---|---|---|
next_cursor | String | Valeur à utiliser dans cursor pour récupérer les résultats précédents. |
previous_cursor | String | Valeur à utiliser dans cursor pour récupérer les résultats suivants. |
results | String | Résultats (cf. ci-dessous). |
result
est sous le format suivant :
Variable | Type | Description |
---|---|---|
id | String | Identifiant unique qui à été rendu à la création de l'identité. |
app_id | String | app_id de l'application dans Seald. |
created | String | Date de la création de l'identité. |
user_id | String | Identifiant 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
Variable | Type | Description |
---|---|---|
user_id (requis*) | String | Identifiant unique qui avait été utilisé pour créer l'utilisateur à supprimer. |
id (requis*) | String | Identifiant 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"}
.