Skip to content

Group TMR Temporary Key

The concept of GroupTMRTemporaryKey is a feature of the Seald SDK that enables joining a group through a 2-man rule mechanism, similar to the storage of identities.

The idea is to protect a group key 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 join the group, 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 join the group.

This feature is particularly useful for adding as recipient to a group a user who is not yet registered on your application, for example when sending them an invitation.

Creating a GroupTMRTemporaryKey

Group members with administrator status can create a GroupTMRTemporaryKey for the group.

To create a GroupTMRTemporaryKey, you need the group ID, and use the method sdk.createGroupTMRTemporaryKey(). This method takes as arguments the ID of the group for which to create the temporary key, as well as an options object:

  • 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 this TmrAccess, must absolutely be the base64 encoding of a cryptographically random 64-byte buffer;
  • isAdmin, a Boolean defining the user's administrator status when joining the group;
  • Optionally, forceGroupUpdate, a Boolean to force the locally known group update before creating the GroupTMRTemporaryKey, defaulting to false.

TIP

To ensure end-to-end confidentiality, the rawOverEncryptionKey must be be accessible only to the person creating the GroupTMRTemporaryKey and to the recipient who will be joining the group.

It is your server's responsibility to store these rawOverEncryptionKey and limit access to the user who creates the GroupTMRTemporaryKey and the invited user.

If multiple users need to add GroupTMRTemporaryKey for the same Auth Factor, you should create different rawOverEncryptionKeys for each one. You can also create a different rawOverEncryptionKey for each addition of GroupTMRTemporaryKey, even if it is the same user adding it for the same Auth Factor, if this is simpler for you.

TIP

The forceGroupUpdate option optimizes network requests, by forcing the before attempting to create a GroupTMRTemporaryKey.

If the locally known group is not up-to-date, creation will fail a first time, and the function will call itself recursively with forceGroupUpdate at true.

The method sdk.createGroupTMRTemporaryKey() returns an object containing the GroupTMRTemporaryKey ID. This ID is not secret, and can be transmitted to your server. It can be used to administer the GroupTMRTemporaryKey, or to choose which GroupTMRTemporaryKey to use to join a group.

Example usage:

javascript
// Each `rawOverEncryptionKey` must necessarily be a 64-byte cryptographically secure random buffer, encoded in base64.
const rawOverEncryptionKey = await sealdSdk.utils.generateB64EncodedSymKey()

// Creating a `GroupTMRTemporaryKey`
const tmrAccess = await sealdSdk.createGroupTMRTemporaryKey(groupInfo.id, {
  rawOverEncryptionKey,
  authFactor: { type: 'EM', value: 'test@example.com' },
  isAdmin: true
})

// Now, you can send the tmrAccess.id with the rawOverEncryptionKey to your servers to save them.
c
SealdError* err = NULL;

char* groupId = "UUID"; // The group ID
char* authFactorType = "EM";
char* authFactorValue = "user@email.com";
int isAdmin = 0; // 1 for admin, 0 otherwise

int rawOverEncryptionKeyLen = 64;
unsigned char* rawOverEncryptionKeyBytes = randomBuffer(rawOverEncryptionKeyLen); // cryptographically random buffer of 64 bytes.

SealdGroupTMRTemporaryKey* gTMRCreated = NULL;
int errCode = SealdSdk_CreateGroupTMRTemporaryKey(sdk1, groupId, authFactorType, authFactorValue, isAdmin, rawOverEncryptionKeyBytes, rawOverEncryptionKeyLen, &gTMRCreated, &err);
objc
NSError* error = nil;

NSString* groupId = @"UUID"; // The group ID

NSData* rawOverEncryptionKey = randomData(64); // cryptographically random buffer of 64 bytes.
        
SealdTmrAuthFactor* tmrAuthFactor = [[SealdTmrAuthFactor alloc] initWithValue:@"user@email.com" type:@"EM"];

SealdGroupTmrTemporaryKey* gTMRKey =  [sdk createGroupTMRTemporaryKeyWithGroupId:groupId
                                                                      authFactor:tmrAuthFactor
                                                                         isAdmin:NO
                                                            rawOverEncryptionKey:rawOverEncryptionKey
                                                                           error:&error];
swift
let groupId = "UUID" // The group ID

let tmrAuthFactor = SealdTmrAuthFactor(value: "user@email.com", type: "EM")

let rawOverEncryptionKey = randomData(64) // cryptographically random buffer of 64 bytes.

let gTMRTKCreated = try await sdk.createGroupTMRTemporaryKeyAsync(
    withGroupId: groupId,
    authFactor: tmrAuthFactor,
    isAdmin: false,
    rawOverEncryptionKey: rawOverEncryptionKey)
kotlin
val groupId = "UUID" // The group ID

val tmrAuthFactor = AuthFactor(AuthFactorType.EM, "user@email.com")
            
val rawOverEncryptionKey = randomData(64) // cryptographically random buffer of 64 bytes.

val gTMRCreated = sdk.createGroupTMRTemporaryKey(groupId, tmrAuthFactor, rawOverEncryptionKey, isAdmin = true)
dart
String groupId = "UUID"; // The group ID

String authFactorType = "EM";
String authFactorValue = "user@email.com";

Uint8List rawOverEncryptionKey = randomData(64); // cryptographically random buffer of 64 bytes.
    
final SealdGroupTMRTemporaryKey gTMRTKCreated =
    await sdk.createGroupTMRTemporaryKeyAsync(groupId, authFactorType,
        authFactorValue, rawOverEncryptionKey);

GroupTMRTemporaryKey administration

There are three functions for administering GroupTMRTemporaryKeys:

TIP

For listGroupTMRTemporaryKeys and searchGroupTMRTemporaryKeys functions, if the all option is set to true, returns all existing pages after the page page.

The functions listGroupTMRTemporaryKeys and searchGroupTMRTemporaryKeys, if the all option is set to true, return all existing pages starting from the page specified by the page parameter.

Convert a GroupTMRTemporaryKey to join a group

To convert a GroupTMRTemporaryKey, 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.convertGroupTMRTemporaryKey() method. This method takes as arguments:

  • groupId, the ID of the group concerned;
  • temporaryKeyId, the ID of the concerned GroupTMRTemporaryKey;
  • the rawOverEncryptionKey used;
  • optionally, a deleteOnConvert option to delete the GroupTMRTemporaryKey after conversion.

Example usage:

javascript
// Retrieving a tmrJWT
const getFactorTokenResponse = await sdk.ssks2MR.getFactorToken({ sessionId: ssksSessionId, authFactor, challenge })

await convertGroupTMRTemporaryKey(
  groupId, // The ID of the groupe to join
  temporaryKeyId, // The ID of the `GroupTMRTemporaryKey` to convert
  getFactorTokenResponse.token, // The token obtained by calling `ssks2MR.getFactorToken()`
  rawOverEncryptionKey, // `rawOverEncryptionKey` transmitted by your server
  { deleteOnConvert: true }
)
c
SealdError* err = NULL;

char* groupId = "UUID"; // The group ID
char* groupTMRKeyId = "UUID"; // The ID of the group TMR key to convert

char* authFactorType = "EM";
char* authFactorValue = "user@email.com";
int deleteOnConvert = 0; // 1 to delete after conversion, 0 otherwise

int rawOverEncryptionKeyLen = 64;
unsigned char* rawOverEncryptionKeyBytes = RETRIEVED_KEY // The `rawOverEncryptionKey` transmitted by your server.


// Retrieve a JWT associated with the authentication factor from SSKS
SealdSsksTMRPlugin* ssksPluginTmrAccesses; // An initialized instance of SealdSsksTMRPlugin
char* authenticationSessionId = "UUID"; // A TMR authentication session created by your server 
char* ssksTMRChallenge = "aaaaaa"; // The challenge sent to the authentication factor
SealdSsksTMRPluginGetFactorTokenResponse* retrievedToken = NULL;
int errCode = SealdSsksTMRPlugin_GetFactorToken(ssksPluginTmrAccesses, authenticationSessionId, authFactorType, authFactorValue, ssksTMRChallenge, &retrievedToken, &err);

// Convert the group TMR temporary key
int errCode = SealdSdk_ConvertGroupTMRTemporaryKey(sdk2, groupId, groupTMRKeyId, retrievedToken->Token, rawOverEncryptionKeyBytes, rawOverEncryptionKeyLen, deleteOnConvert, &err);
objc
NSError* error = nil;

NSString* groupId = @"UUID"; // The group ID
NSString* groupTMRKeyId = @"UUID"; // The ID of the group TMR key to convert

NSData* rawOverEncryptionKey = RETRIEVED_KEY // The `rawOverEncryptionKey` transmitted by your server.

SealdTmrAuthFactor* tmrAuthFactor = [[SealdTmrAuthFactor alloc] initWithValue:@"user@email.com" type:@"EM"];

// Retrieve a JWT associated with the authentication factor from SSKS
NSString* authenticationSessionId = @"UUID"; // A TMR authentication session created by your server 
NSString* ssksTMRChallenge = @"aaaaaa"; // The challenge sent to the authentication factor
SealdSsksGetFactorTokenResponse* tmrJWT = [ssksTMR getFactorToken:authenticationSessionId
                                                       authFactor:tmrAuthFactor
                                                        challenge:ssksTMRChallenge
                                                            error:&error];

// Convert the group TMR temporary key  
[sdk2 convertGroupTMRTemporaryKeyWithGroupId:groupTMRId
                                      temporaryKeyId:gTMRKey.keyId
                                              tmrJWT:tmrJWT.token
                                rawOverEncryptionKey:rawOverEncryptionKey
                                     deleteOnConvert:NO
                                               error:&error];
swift
let groupId = "UUID" // The group ID
let groupTMRKeyId = "UUID" // The ID of the group TMR key to convert

let tmrAuthFactor = SealdTmrAuthFactor(value: "user@email.com", type: "EM")

let rawOverEncryptionKey = RETRIEVED_KEY // The `rawOverEncryptionKey` transmitted by your server.

// Retrieve a JWT associated with the authentication factor from SSKS
let authenticationSessionId = "UUID"// A TMR authentication session created by your server 
let ssksTMRChallenge = "aaaaaa" // The challenge sent to the authentication factor
let tmrJWT = try await ssksTMR.getFactorTokenAsync(
    sessionId: authenticationSessionId,
    authFactor: tmrAuthFactor,
    challenge: ssksTMRChallenge
)

// Convert the group TMR temporary key  
try await sdk.convertGroupTMRTemporaryKeyAsync(
    withGroupId: groupId,
    temporaryKeyId: groupTMRKeyId,
    tmrJWT: tmrJWT.token,
    rawOverEncryptionKey: rawOverEncryptionKey,
    deleteOnConvert: false)
kotlin
val groupId = "UUID" // The group ID
val groupTMRKeyId = "UUID" // The ID of the group TMR key to convert

val tmrAuthFactor = AuthFactor(AuthFactorType.EM, "user@email.com")
            
val rawOverEncryptionKey = RETRIEVED_KEY // The `rawOverEncryptionKey` transmitted by your server.

// Retrieve a JWT associated with the authentication factor from SSKS
val authenticationSessionId = "UUID" // A TMR authentication session created by your server
val ssksTMRChallenge = "aaaaaa" // The challenge sent to the authentication factor
val tmrJWT =
    ssksPlugin.getFactorTokenAsync(
        authenticationSessionId,
        authFactor = tmrAuthFactor,
        challenge = ssksTMRChallenge,
    )

// Convert the group TMR temporary key
sdk.convertGroupTMRTemporaryKey(groupId, groupTMRKeyId, tmrJWT.token, rawOverEncryptionKey)
dart
String groupId = "UUID"; // The group ID
String groupTMRKeyId = "UUID"; // The ID of the group TMR key to convert

String authFactorType = "EM";
String authFactorValue = "user@email.com";

Uint8List rawOverEncryptionKey = RETRIEVED_KEY // The `rawOverEncryptionKey` transmitted by your server.

// Retrieve a JWT associated with the authentication factor from SSKS
String authenticationSessionId = "UUID"; // A TMR authentication session created by your server
String ssksTMRChallenge = "aaaaaa"; // The challenge sent to the authentication factor
SealdSsksTMRPluginGetFactorTokenResponse tmrJWT =
    await ssksPlugin.getAuthFactorTokenAsync(
        authenticationSessionId, authFactorType, authFactorValue,
        challenge: ssksTMRChallenge);

// Convert the group TMR temporary key 
await sdk2.convertGroupTMRTemporaryKeyAsync(
    groupId, groupTMRKeyId, tmrJWT.token, rawOverEncryptionKey);