Backup key and custodians
client.backupKey, the BackupKey namespace, creates and maintains the tenant’s backup key for break-glass recovery. It splits the key across custodians. No single custodian and no device alone can rebuild it. An Owner creates the key once, with three to seven custodians. The quorum is from two up to one fewer than the number of custodians. Create the key before the tenant registers its first dataset.
The calls
The samples use the allowed helper from Access decisions.
const registration = await client.backupKey.registration();// { registrationId, state, fingerprint, custodians: [{ person, received, lastProvedAt }], quorum, mintedBy, mintedAt } | undefined
// the caller holds the Owner roleawait allowed(await client.backupKey.mint({ custodians: [alice, bob, carol], quorum: 2 }));if (registration?.state === 'pending') await client.backupKey.abandon(registration.registrationId); // before the registration completes
// a custodian, from the worklistconst delivery = await client.backupKey.receiveShare(registration.registrationId);// { registrationId, fingerprint, code?, receipt() }if (delivery.code) await printForPerson(delivery.code, delivery.fingerprint);await delivery.receipt();
// once a year, as the floor requiresconst { held } = await client.backupKey.proveShare({ code: await askForCode() });const { held: heldByToken } = await client.backupKey.proveShare({ medium: 'token' });
// replaces a custodian. The fingerprint and every pin stay the same.const ceremony = await allowed(await client.backupKey.replaceCustodian({ leaving: bob, joining: carol }));let registration = try await client.backupKey.registration()
_ = try await allowed(client.backupKey.mint(custodians: [alice, bob, carol], quorum: 2))if let registration, registration.state == .pending { try await client.backupKey.abandon(registration.registrationId) }
let delivery = try await client.backupKey.receiveShare(registration!.registrationId)if let code = delivery.code { try await printForPerson(code, delivery.fingerprint) }try await delivery.receipt()
let proof = try await client.backupKey.proveShare(.code(await askForCode()))let tokenProof = try await client.backupKey.proveShare(.token)
let ceremony = try await allowed(client.backupKey.replaceCustodian(leaving: bob, joining: carol))val registration = client.backupKey.registration()
allowed(client.backupKey.mint(custodians = listOf(alice, bob, carol), quorum = 2))if (registration?.state == BackupKeyRegistration.State.PENDING) client.backupKey.abandon(registration.registrationId)
val delivery = client.backupKey.receiveShare(registration!!.registrationId)delivery.code?.let { printForPerson(it, delivery.fingerprint) }delivery.receipt()
val proof = client.backupKey.proveShare(ShareInput.Code(askForCode()))val tokenProof = client.backupKey.proveShare(ShareInput.Token)
val ceremony = allowed(client.backupKey.replaceCustodian(leaving = bob, joining = carol))A BackupKeyRegistration carries:
state:pendinguntil every named custodian’sreceivedistrue, thencompletefingerprint: what every device pins the first time it opens a session in the tenantmintedByandmintedAt: who created the key and whenquorum: how many custodians must present a share together to rebuild the key
Proving a share (proveShare, which sets lastProvedAt) is a separate yearly duty that the floor requires. It does not gate completion.
A custodian’s ShareInput is either the printed code they read out, or { medium: 'token' }. The tenant uses the token form when it issued a hardware token through the offline medium adapter instead of a printed code.
What the SDK does for you
mintcreates the key and gives each custodian their own share, as aShareDelivery. In the same call, it signs the registration after a fresh multi-factor sign-in.- The SDK discards a custodian’s share from memory the moment
receipt()orproveSharefinishes with it. The Seald Healthcare Cloud deletes the wrapped share onreceipt(). The SDK keeps only a signed commitment. replaceCustodiangives the new set of custodians shares of the same key, without changing the key. Thefingerprintand every device’s pin stay the same. No device needs to trust anything new.- Raises a
custodian-shareworklist item as soon as a custodian’s share is ready to collect. - Raises a
proof-overdueworklist item when a custodian’s yearly proof is late.
Decisions and errors you may see
Outcome or ErrorCode | When | What to do |
|---|---|---|
deny on mint | The caller does not hold the Owner role, or named fewer than three or more than seven custodians. | Ask an Owner to create the key with three to seven custodians. |
fingerprint-mismatch | A device’s pinned fingerprint no longer matches the registration. | Do not proceed. Contact support before creating the key again. |
{ held: false } from proveShare | The presented share does not match its commitment. | Ask the custodian to check their offline copy, or start replaceCustodian. |
challenge | The caller’s multi-factor sign-in is no longer fresh. | Call stepUp(), or use the allowed helper. |