Skip to content

SSKS API

The default URL of SSKS is ssks.seald.io.

Headers of the requests

Authentication is done through HTTP headers:

VariableTypeDescription
X-SEALD-APPID (required)StringApplication ID, given on the Seald SDK administration dashboard
X-SEALD-APIKEY (required)StringAPI key, given on the Seald SDK administration dashboard
Content-typeStringapplication/json

To learn where you can get these, you can check the paragraph about it in the 2-man-rule integration guide.

Requests for 2-man rule protection

Sending a challenge

This API endpoint is called by the application server using the SDK, and allows to:

  • Create a "user" in the sense of SSKS (if create_user is set to true);
  • Create a "Session";
  • If an identity has previously been stored onto SSKS with this auth_factor (email address or phone number, see the Checking must_authenticate paragraph for details on the comparaison), or if force_auth is set to true, then must_authenticate is set to true; otherwise, to false;
  • Return a session_id and must_authenticate;
  • If must_authenticate is true, send a challenge to the user, by email or SMS, the backend must not have access to this challenge. The challenge is valid for 6h.

The backend must return the session_id and must_authenticate to the frontend, as explained in the 2-man-rule integration guide.

TIP

Sending challenges by SMS is limited to the SMS quota authorized for your team. If the quota is exceeded, your request will receive an error 406 Not Acceptable: {"detail": "SMSQuotaFailed"}.

Do not hesitate to contact us to increase the SMS quota for your team.

URL

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

Format of the request body

This is a POST request in JSON format:

VariableTypeDescription
create_user (default: false)BooleanIf true, creates a user if it does not exist. Otherwise rejects with a 404 error. If unused, the application must manually create a user
user_id (required)StringUnique identifier of the user. Can be an ID, a UUID, an email address or any string identifier unique to this user in the context of your application. The data is stored in clear text on SSKS.
auth_factor (required)ObjectAuthentication method of this user. Used to send the challenge. Can be the same for multiple users as long as the user_id is unique.
auth_factor.type (required)StringType of authentication factor. "EM" for email address, "SMS" for phone number.
auth_factor.value (required)StringUser's email address or phone number. Used to send the challenge. Must be normalized. It is not stored in clear text on SSKS, check the Storage of authFactors paragraph for details.
email (deprecated)StringDeprecated, use auth_factor. User's email address.
force_auth (default: false)BooleanThis forces the sending of an authentication challenge, even if this auth_factor has never been used before.
template (required)StringTemplate in HTML format of the email sent to the user containing the authentication challenge. Must contain the String $$CHALLENGE$$ which will be replaced by the challenge by SSKS.
subjectStringSubject line of the email containing the challenge. Defaults to "End-to-end encryption challenge". Ignored in case of SMS.
fake_otp (default: false)BooleanOnly in test / staging environment. If true, email or SMS won't be sent. The challenge will always be aaaaaaaa. If true in production environment, a 406 error will be thrown.

TIP

For sending SMS to United-States phone numbers, a template pre-checking may be required.

Please contact us in order to set it up.

Format of the response

In JSON format:

VariableTypeDescription
session_idStringID of the newly created session. Must be transmitted to the frontend.
must_authenticateBooleanBoolean indicating if the newly created session needs a challenge. If true, the server sends an email to the user, containing this challenge, which they will need to repeat in the frontend in the next 6h. If false, the session can directly save the identity on SSKS without a challenge.
task_idStringIf the challenge takes less than 3s to be sent to the user, this field will be None. Otherwise, task_id will be a String, to be used with /tmr/back/check_task/ to follow-up with sending status.

Checking task_id status

This API endpoint can be used by the server when sending a challenge takes more than 3 seconds.

In that case, /tmr/back/challenge_send/ should have returned a task_id that can be used in this API endpoint.

TIP

Tasks are deleted 24h after success. In that case, checking an old, succeeded task might not return a SUCCESS status.

URL

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

Format of the request body

This is a POST request in JSON format:

VariableTypeDescription
task_idStringValue of the task_id given in /tmr/back/challenge_send/.

Format of the response

In JSON format:

VariableTypeDescription
statusStringSUCCESS when the challenge is sent to the user. FAILURE or REVOKED when sending the challenge has failed. Other when the task is being processed.

Checking must_authenticate

This API endpoint can be used by the server of the app that uses the SDK before sending a challenge to check what value must_authenticate would take if the send challenge endpoint were called.

It allows checking if an identity has already been stored for a given auth_factor.

TIP

To decide the value of must_authenticate, the SSKS server does not simply use the raw authentication factor given by the request to check whether an identity has previously been stored with it or not. It also tries to remove any aliases potentially present.

For example, for Gmail email addresses, anything after the + is ignored: email@gmail.com and email+alias@gmail.com are considered equivalent.

The exact procedure used to do this is subject to be changed and improved.

URL

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

Format of the request body

This is a POST request in JSON format:

VariableTypeDescription
type (required)StringType of authentication factor. "EM" for email address, "SMS" for phone number.
value (required)StringUser's email address or phone number. Must be normalized.

Format of the response

In JSON format:

VariableTypeDescription
must_authenticateBooleanBoolean indicating if the newly created session needs a challenge. If true, the server would send an email or SMS to the user if the send_challenge endpoint were to be used.

Manual creation of a user

This API point can be used if create_user is set to False on the previous API point. This will just create a blank "user" in the sense of SSKS.

URL

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

Format of the request body

VariableTypeDescription
user_id (required)StringUnique identifier of the user. Can be an ID, a UUID, an email address or any string identifier unique to this user in the context of your application. The data is stored in clear text on SSKS.
auth_factor (required)ObjectAuthentication method of this user. Used to send the challenge.
auth_factor.type (required)StringType of authentication factor. 'EM' for email address, 'SMS' for phone number.
auth_factor.value (required)StringUser's email address or phone number. Must be normalized. It is not stored in clear text on SSKS, check the Storage of authFactors paragraph for details.
email (deprecated)StringDeprecated, use auth_factor. User's email address.

Response

This API point does not have any information to return to the server. It simply responds with {"status": "ok"}.

Deletion of a user

This API point can be used to delete all data stored on a user on SSKS.

URL

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

Format of the request body

VariableTypeDescription
user_id (required)StringUnique identifier that was used to create the user to delete.
auth_factor (optional)ObjectObject containing information regarding user authentication. If used, only the user with corresponding auth_factor will be deleted. (It can be useful is there are multiple users with the same user_id)
auth_factor.type (required if auth_factor is used)StringType of authentication factor. 'EM' for email address, 'SMS' for phone number.
auth_factor.value (required if auth_factor is used)StringUser's email address or phone number. Must be normalized.
full_forget (optional)BooleanOnly in test / staging environment. If true, completely delete the user, to avoid must_authenticate being true when storing another identity with the same factor. If true in production environment, a 406 error will be thrown.

Response

VariableTypeDescription
statusStringok if the request performed correctly
deletedNumberNumber of identities deleted

Checking an identity exists

This API point can be used to check if a given user_id (possibly with a specific auth_factor) has a 2-man-rule protected identity.

It responds with the number of identities corresponding to that user, either 0 when there is none or the user does not exists, or a stricly positive integer if there is one or more.

It is also possible to check if there is an identity stored for a user_id without checking the auth_factor it is associated with.

URL

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

Format of the request body

VariableTypeDescription
user_id (required)StringUnique identifier that was used to create the user to check.
auth_factor (optional)ObjectAuthentication method of this user. Used to send the challenge.
auth_factor.type (required if auth_factor.value is given)StringType of authentication factor. 'EM' for email address, 'SMS' for phone number.
auth_factor.value (required if auth_factor.type is given)StringUser's email address or phone number. Must be normalized.

Response

VariableTypeDescription
identities_countNumberNumber of identities stored for this user_id, maybe filtered with the auth_factor.
userObjectData about the requested user
user.user_idObjectuser_id given in the request
user.app_idObjectapp_id of the application for Seald

Retrieve identities

This API point can be used to retrieve information regarding stored identities.

URL

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

Format of request parameters

VariableTypeDescription
cursorStringTo be used in order to retrieve previous or next results in case of many results.
user_idStringUnique identifier used to create the user.
idStringUnique identifier returned when creating the user.

Response

This API point returns the following information in a paginated way.

VariableTypeDescription
next_cursorStringValue to use in cursor in order to retrieve next results.
previous_cursorStringValue to use in cursor in order to retrieve previous results.
resultsStringResults (see below).

result follows this schema :

VariableTypeDescription
idStringUnique identifier returned when creating the user.
app_idStringapp_id of the application for Seald.
createdStringIdentity date of creation
user_idStringUnique identifier used to create the user.
auth_factor_typeStringType of authentication factor. 'EM' for email address, 'SMS' for phone number.
hash_convertedBooleanTrue if the authentication factor value has been converted once.
hash_v2_convertedBooleanTrue if the authentication factor value has been converted twice.

Deleting an identity (2)

This API endpoint can be used to remove the identity corresponding to a given id, or all identities stored for a given user_id.

URL

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

Format of request parameters

VariableTypeDescription
user_id (required*)StringUnique identifier used to create the user.
id (required*)StringUnique identifier returned when creating the user.

* One of user_id or id is required, but not both. Using only one of those parameters is enough.

Response

This API point does not have any information to return to the server. It simply responds with {"status": "ok"}.

Normalization of authFactors

When using SSKS for 2-man-rule protection, all authFactors sent to SSKS must be normalized. If an authFactor is sent in a non-normalized manner the SSKS server may return an error.

WARNING

For the time being, non-normalized authFactors are still accepted, and are normalized internally by the server.

However, they are deprecated, and will be rejected in a few months.

Email normalization

Email addresses are normalized by:

  • normalizing the string encoding to NFKC
  • removing spaces
  • making the string lowercase

To do this normalization, you can use the following snippets:

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

Normalizing phone numbers

For phone numbers, they must be sent in international standard format E.164.

This is simply the phone number, without any spaces, preceded by the country code noted with a +.

For example, the following notations are NOT valid:

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

Use the following notation:

+33123456789

To convert any phone number to E.164. format, libraries exist in different languages. For example, to convert a number to E.164 considering that we are in France:

  • in Python, you can use 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'
  • in JavaScript, you can use 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'

Storage of authFactors

The value of authentication factors is not stored in clear text on SSKS. It is first normalized, then hashed. The hash is stored so that it can be verified that the value given is the same when used later.

Also, a de-aliased version is computed, then hashed and stored, so that the SSKS can decide the value of must_authenticate for later requests.

Finally, the auth_factor is also encrypted for a key that the server does not possess, and this encrypted version is stored, so that Seald is able to, if necessary in the future, migrate the hashing procedures.

Migration

As of 01/31/2022, the hash function has been updated from v1 to v2 to improve performance by reducing the number of hash iterations.

As of 01/01/2023, the hash function has been updated from v2 to v3 by introducing prior normalization, as well as a de-aliasing mechanism to ensure that a change in case or encoding of the authFactor is not treated as a different authFactor, and that the use of common email aliases does not circumvent authentication.

Since the value of authFactor for which an encrypted identity has been stored in v1 or v2 is not accessible by our teams, we cannot compute the v3 hash for them. Therefore, a migration mechanism has been implemented:

When a request containing an authFactor (POST /tmr/back/challenge_send/, POST /tmr/back/must_authenticate/, POST /tmr/back/delete_user/, POST /tmr/back/identity_check/), SSKS computes the v3 hash, the v2 hash, and the v1 hash, then:

  1. if the authFactor has no match on the v3 hash, but has one on the v1 or v2 hash, the authFactor is migrated to the v3 hash and the old hash is deleted.
  2. if the authFactor has a match on the v3 hash and has a match on the v1 or v2 hash, a normalization-related collision has occurred which notifies the Seald teams and responds to the client with a 500 error. In this case, the collision must be handled manually, please contact us at support@seald.io.
  3. Otherwise, the authFactor has a match on the v3 hash, and not on the v1 and v2 hash, which is the normal operation.

DANGER

It is crucial to perform the migration with the raw, unnormalized value of the authFactor, as given when storing the user's identity. Otherwise, the server would not be able to find the match with the old v1 hash or v2 hash.

Once the migration of your app is completed, it is recommended to send only the normalized version of the authFactor.

TIP

Once all users of an application have been migrated to a hash version (v2 or v3), the hashes of previous versions are no longer calculated. In particular, the performance improvement linked to the introduction of the v2 hash is only effective once all users have been migrated to the v2 hash at least.

Perform migration

To perform the migration on all users, you must:

  • For each user in your application:
    • For each authFactor of that user:
      • Make an authenticated call to POST /tmr/back/must_authenticate/ with parameters { "type": <"EM"|"SMS">, "value": <value> }. Please note: you must send the raw, unnormalized value of the authFactor as given when storing the user's identity for the migration to work.

Once done, all known users in your application have been migrated.

You may have other unused identities in your application that should be deleted. To confirm that your migration is complete, please contact us at support@seald.io.

Once you have confirmed with Seald that all users have been migrated, you can normalize the authFactor registered in your application.

Requests for password protection

Checking an identity exists

This API endpoint can be used to check if a given user_id has one or more identities stored protected with a passsword.

It responds with identities_count which represents how many identities there are for this user. It can either be 0 if there are none, or a strictly positive integer.

URL

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

Format of the request body

VariableTypeDescription
user_id (required)StringUnique identifier that was used to create the user to check.

Response

VariableTypeDescription
identities_countNumberNumber of identities stored for this user_id.
userObjectData about the requested user
user.user_idObjectuser_id given in the request
user.app_idObjectapp_id of the application for Seald

Deleting an identity

This API endpoint can be used to remove all identities stored for a given user_id.

It is not possible to distinguish different identities of a user. Therefore, it is only possible to remove them jointly.

URL

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

Format of the request body

VariableTypeDescription
user_id (required)StringUnique identifier that was used to create the user to delete.

Response

This API point does not have any information to return to the server. It simply responds with {"status": "ok"}.

Retrieve identities

This API point can be used to retrieve information regarding stored identities.

URL

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

Format of request parameters

VariableTypeDescription
cursorStringTo be used in order to retrieve previous or next results in cas of many results.
user_idStringUnique identifier used to create the user.
idStringUnique identifier returned when creating the user.

Response

This API point returns the following information in a paginated way.

VariableTypeDescription
next_cursorStringValue to use in cursor in order to retrieve next results.
previous_cursorStringValue to use in cursor in order to retrieve previous results.
resultsStringResults (see below).

result follows this schema :

VariableTypeDescription
idStringUnique identifier returned when creating the user.
app_idStringapp_id of the application for Seald.
createdStringIdentity date of creation.
user_idStringUnique identifier used to create the user.

Deleting an identity (2)

This API endpoint can be used to remove the identity corresponding to a given id, or all identities stored for a given user_id.

URL

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

Format of request parameters

VariableTypeDescription
user_id (required*)StringUnique identifier used to create the user.
id (required*)StringUnique identifier returned when creating the user.

* One of user_id or id is required, but not both. Using only one of those parameters is enough.

Response

This API point does not have any information to return to the server. It simply responds with {"status": "ok"}.