Use this file to discover all available pages before exploring further.
Matrix server-side secret storage (also called 4S or SSSS) is a mechanism for storing sensitive cryptographic material — such as cross-signing private keys and the key backup decryption key — encrypted on the homeserver. This allows you to access those secrets from new devices using a single recovery key.
Secret storage should be set up before calling bootstrapCrossSigning or enabling key backup, so that newly created private keys can be stored immediately.
Generating a secret storage key (the recovery key) on the client.
Encrypting secrets (cross-signing keys, key backup key) with that key.
Uploading the encrypted blobs to the homeserver as account data.
When a new device needs those secrets, it calls getSecretStorageKey to retrieve the recovery key from the user, which is then used to decrypt the blobs from account data.The algorithm used is m.secret_storage.v1.aes-hmac-sha2, defined in secret-storage.ts:
To access secret storage, provide getSecretStorageKey in the cryptoCallbacks option when creating the client. This callback is called whenever the crypto stack needs to decrypt something from secret storage:
import * as sdk from "matrix-js-sdk";const matrixClient = sdk.createClient({ baseUrl: "http://localhost:8008", accessToken: myAccessToken, userId: myUserId, cryptoCallbacks: { /** * Called when the crypto stack needs to access secret storage. * Prompt the user to enter their recovery key and return it. * * @param opts.keys - Map from key ID to SecretStorageKeyDescription. * @param name - The name of the secret being accessed. * @returns [keyId, privateKeyBytes] or null if unknown. */ getSecretStorageKey: async ({ keys }, name) => { const recoveryKey = await promptUserForRecoveryKey(); // Return the key ID and the raw private key bytes const keyId = Object.keys(keys)[0]; return [keyId, recoveryKey]; }, /** * Optional. Called when a new secret storage key is created. * Use this to cache the key temporarily so getSecretStorageKey * doesn't have to prompt the user again in the same session. */ cacheSecretStorageKey: (keyId, keyInfo, key) => { sessionKeyCache.set(keyId, key); }, },});
The secret storage key may be requested multiple times in quick succession during bootstrapSecretStorage. Use cacheSecretStorageKey to cache it temporarily and avoid prompting the user repeatedly.
CryptoApi.bootstrapSecretStorage() is idempotent — it only sets up secret storage if it is not already configured. Call it unconditionally after initRustCrypto():
await matrixClient.initRustCrypto();const crypto = matrixClient.getCrypto();await crypto.bootstrapSecretStorage({ /** * Called only when a new secret storage key needs to be created. * You MUST prompt the user to save this key, as they will need it * to unlock secret storage on new devices. */ createSecretStorageKey: async () => { const key = await crypto.createRecoveryKeyFromPassphrase(); // Display key.encodedPrivateKey to the user and ask them to save it. await showRecoveryKeyToUser(key.encodedPrivateKey); return key; },});
When secret storage has not yet been set up, bootstrapSecretStorage calls createSecretStorageKey to generate a new key. The callback must return a GeneratedSecretStorageKey:
export interface GeneratedSecretStorageKey { keyInfo?: { /** If the key was derived from a passphrase, information on that derivation. */ passphrase?: PassphraseInfo; /** Optional human-readable name for the key. */ name?: string; }; /** The raw generated private key. */ privateKey: Uint8Array<ArrayBuffer>; /** * The generated key, encoded for display to the user per * https://spec.matrix.org/v1.7/client-server-api/#key-representation */ encodedPrivateKey?: string;}
Use CryptoApi.createRecoveryKeyFromPassphrase() to generate the key:
const key = await crypto.createRecoveryKeyFromPassphrase();// key.encodedPrivateKey is a human-readable string like:// "EsTT qPME mVyg 9rIF ..."await showAndConfirmRecoveryKey(key.encodedPrivateKey);return key;
encodedPrivateKey must be displayed to the user and saved somewhere safe before the callback returns. There is no way to recover it later without re-running the setup flow with setupNewSecretStorage: true.
The following is the full pattern recommended in the matrix-js-sdk README:
const matrixClient = sdk.createClient({ baseUrl: "http://localhost:8008", accessToken: myAccessToken, userId: myUserId, cryptoCallbacks: { getSecretStorageKey: async (keys) => { // This function should prompt the user to enter their secret storage key. return mySecretStorageKeys; }, },});await matrixClient.initRustCrypto();await matrixClient.getCrypto().bootstrapSecretStorage({ // This function will be called if a new secret storage key (aka recovery key) is needed. // You should prompt the user to save the key somewhere, because they will need it // to unlock secret storage in future. createSecretStorageKey: async () => { return mySecretStorageKey; },});