TMR Accesses
The concept of TmrAccesses
is a feature of the Seald SDK that enables retrieving an EncryptionSession
through a 2-man rule mechanism, similar to the storage of identities.
The idea is to protect an EncryptionSession
for a certain Auth Factor (an email address, or a phone number), with a specific overEncryptionKey
that will be stored by your servers (like the twoManRuleKey
for identity storage).
Then, when the recipient wants to retrieve it, they receive a challenge
by email or SMS, valid for 6 hours, and must repeat it in the application to prove they control the Auth Factor, and can access the EncryptionSession
.
This feature is particularly useful for adding as recipient to an EncryptionSession
a user who is not yet registered on your application, for example when sending them an invitation.
Creating a TmrAccess
The user who created an EncryptionSession
, or any user who has access and the forward
right, can create a TmrAccess
for this EncryptionSession
.
To create a TmrAccess
, retrieve the EncryptionSession
object, and use the session.addTmrAccess()
method. This method takes as argument tmrRecipients
, which is an Array
of TmrRecipientWithRights
. Each element of this Array
contains three fields:
authFactor
, which itself contains the type of the Auth Factor used ('EM'
for an email address,'SMS'
for a phone number), and the value of this Auth Factor;rawOverEncryptionKey
, which is the key to protect thisTmrAccess
, must absolutely be the base64 encoding of a cryptographically random 64-byte buffer;- optionally,
rights
that define the rights for thisTmrAccess
.
TIP
To ensure end-to-end confidentiality, the rawOverEncryptionKey
should only be accessible to the person creating the TmrAccess
and the session recipient.
It is your server's responsibility to store these rawOverEncryptionKey
and limit access to the user who creates the TmrAccess
and the invited user.
If multiple users need to add TmrAccesses
for the same Auth Factor, you should create different rawOverEncryptionKey
s for each one. You can also create a different rawOverEncryptionKey
for each addition of TmrAccess
, even if it is the same user adding it for the same Auth Factor, if this is simpler for you.
You can also specify rights for the recipient of this TmrAccess
with the rights
argument. When the user converts a TmrAccess
into normal access, these rights will be converted with it.
TIP
The default rights
for a TmrAccess
are { read: true, forward: true, revoke: false }
.
The session.addTmrAccess()
method returns the ID of the created TmrAccess
. This ID is not secret, and can be sent to your server. It can be used to manage the TmrAccess
, or to choose which TmrAccess
to use to retrieve a session.
Example usage:
// Each `rawOverEncryptionKey` must necessarily be a 64-byte cryptographically secure random buffer, encoded in base64.
const rawOverEncryptionKey = await sealdSdk.utils.generateB64EncodedSymKey()
// Creating `TmrAccess`
const tmrAccessId = await session.addTmrAccess({
authFactor: { type: 'EM', value: 'test@example.com' },
rawOverEncryptionKey,
rights: { read: true, forward: false, revoke: false }
})
// Now, you can send the tmrAccessId with the rawOverEncryptionKey to your servers to save them.
TIP
If you need to add multiple TmrAccesses
to the same EncryptionSession
, for multiple recipient Auth Factors for example, you can also use the session.addMultipleTmrAccesses() method. the session.addMultipleTmrAccesses()
method. This has a more complex return type, detailed in its reference. This has a more complex return type, detailed in its reference.
Retrieving a session with a TmrAccess
To retrieve an EncryptionSession
via a TmrAccess
, one must first prove that they control the recipient's Auth Factor. To do this, obtain a JWT from the SSKS server with the ssks2MR.getFactorToken()
method. This method, of course, requires being authenticated with SSKS, that is either having an authenticatedSessionId
, or using the POST /tmr/back/challenge_send/
API endpoint (with force_auth
to true
) to obtain a challenge, and passing this challenge during the call to ssks2MR.getFactorToken()
.
Then, once you have this token, use the sdk.retrieveEncryptionSessionByTmr()
method. This method takes as arguments:
- the ID of the
EncryptionSession
; - the token provided by
ssks2MR.getFactorToken()
; - the
rawOverEncryptionKey
used; - optionally, options (including filtering) detailed below.
The sdk.retrieveEncryptionSessionByTmr()
method returns an EncryptionSession
, which then allows for encrypting/decrypting messages and files.
TIP
If you access an EncryptionSession
via a TmrAccess
, you cannot use the access management methods of that session (session.addRecipients()
, session.addSymEncKey()
, session.revokeRecipients()
, session.listRecipients()
, ...) without having converted it.
Example of simple usage:
// Retrieving a tmrJWT
const getFactorTokenResponse = await sdk.ssks2MR.getFactorToken({ sessionId: ssksSessionId, authFactor, challenge })
// Retrieving an EncryptionSession with a `TmrAccess`
const encryptionSession = await sdk.retrieveEncryptionSessionByTmr(
encryptionSessionId, // `encryptionSessionId` is not secret, and can be transmitted via your server
getFactorTokenResponse.token, // The token obtained by calling `ssks2MR.getFactorToken()`
rawOverEncryptionKey // `rawOverEncryptionKey` transmitted by your server
)
Warning, if there are multiple TmrAccesses
for the same Auth Factor and the same EncryptionSession
, by default retrieveEncryptionSessionByTmr()
will throw an error. Indeed, this function must know which TmrAccess
to use, that is, which one corresponds to the passed rawOverEncryptionKey
.
For this, retrieveEncryptionSessionByTmr()
accepts an options object, which contains the following optional arguments:
useCache
: a boolean, which defaults totrue
. Indicates to try retrieving the session from the cache;tmrAccessId
: the ID of theTmrAccess
to use. If you have it, it is recommended to always pass it, to avoid any problems;createdById
: the ID of the user who added theTmrAccess
to use;tryIfMultiple
: a boolean, which defaults tofalse
. If set totrue
, and if the other optionally passed filters match multipleTmrAccesses
, indicates to iterate over all retrievedTmrAccesses
to find on which the passedrawOverEncryptionKey
works, instead of returning an error.
Example usage with options:
// Retrieving a tmrJWT
const getFactorTokenResponse = await sdk.ssks2MR.getFactorToken({ sessionId: ssksSessionId, authFactor, challenge })
// Retrieving an EncryptionSession with a `TmrAccess`
const encryptionSession = await sdk.retrieveEncryptionSessionByTmr(
encryptionSessionId, // `encryptionSessionId` is not secret, and can be transmitted via your server
getFactorTokenResponse.token, // The token obtained by calling `ssks2MR.getFactorToken()`
rawOverEncryptionKey, // `rawOverEncryptionKey` given by your server
{
tmrAccessId // retrieves the session via the TmrAccess that corresponds to this ID
}
)
Converting TmrAccesses
into a normal accesses
You can also convert a TmrAccess
into a normal access to the corresponding EncryptionSession
. This mechanism can be useful if the TmrAccess
was created as an invitation for a user who does not yet have a Seald account to access an EncryptionSession
. Once they have created their Seald account, the TmrAccesses
intended for them can be converted into normal accesses, allowing their Seald account to access the corresponding EncryptionSessions
in the future without undergoing a 2-Man-Rule authentication each time.
To convert a TmrAccess
into normal access to the EncryptionSession
, one must first prove that they control the recipient's Auth Factor. To do this, obtain a JWT from the SSKS server with the ssks2MR.getFactorToken()
method. This method, of course, requires being authenticated with SSKS, that is either having an authenticatedSessionId
, or using the POST /tmr/back/challenge_send/
API endpoint (with force_auth
to true
) to obtain a challenge, and passing this challenge during the call to ssks2MR.getFactorToken()
.
Then, once you have this token, you must use the sdk.convertTmrAccesses()
method. This method takes as arguments:
- the token issued by
ssks2MR.getFactorToken()
; - the
rawOverEncryptionKey
used; - optionally, options (including filtering) detailed below.
This method retrieves all the TmrAccesses
matching the given filters, and converts them into normal access to the corresponding EncryptionSession
.
WARNING
It is required that all the TmrAccesses
matching these filters be protected by the same rawOverEncryptionKey
!
For this, convertTmrAccesses()
accepts an options object, which contains the following optional arguments:
deleteOnConvert
: a boolean, which defaults totrue
. Indicates to delete theTmrAccesses
after their conversion into normal accesses;sessionId
: the ID of theEncryptionSession
for which to convert aTmrAccess
;tmrAccessId
: the ID of theTmrAccess
to convert;createdById
: the ID of the user who added theTmrAccesses
to convert.
TIP
Since it is recommended to have a different rawOverEncryptionKey
for each sender, and since the call to convertTmrAccesses()
must absolutely contain filters that limit it to TmrAccesses
having the same rawOverEncryptionKey
, it is recommended to always specify createdById
.
Example of use:
// Retrieving a tmrJWT
const getFactorTokenResponse = await sdk.ssks2MR.getFactorToken({ sessionId: ssksSessionId, authFactor, challenge })
// Converting TmrAccesses
const result = await sdk.convertTmrAccesses(
getFactorTokenResponse.token, // The token obtained by the call to `ssks2MR.getFactorToken()`
rawOverEncryptionKey, // `rawOverEncryptionKey` transmitted by your server
{
createdById, // converts only the TmrAccesses created by the user corresponding to this SealdID
sessionId: encryptionSessionId // converts only the TmrAccesses corresponding to this EncryptionSession
}
)
// Here, one can check `result` to see if the conversion was successful
// Now, the user can retrieve the session directly
const encryptionSession = await sdk.retrieveEncryptionSession({ sessionId: encryptionSessionId })