Guardian Recovery Ceremony Flow
Account recovery via 2-of-3 guardian-based ceremony with time-lock delay. Users pre-register 3 guardians during account setup. Recovery requires 2 guardian approvals with a mandatory time-lock delay. MPC key shares are never exposed during recovery - only the account authentication binding is updated to the new credential.
Six steps from initiation to credential binding update.
User Initiates Recovery
User has lost their passkey or password and accesses the recovery page from a new device. They submit a recovery request identifying their account and providing a new credential.
Endpoint: POST /wallet/recovery/start
Payload: account_id, zone_id (protected), old_credential_id_b64u, new_credential_id_b64u, timelock_seconds (default 30)
Recovery Ceremony Created
The recovery-ceremony service creates a ceremony record in PostgreSQL and returns a unique ceremony_id to the user. The ceremony is now in pending status. The record includes the old credential commitment (hashed for privacy), new credential ID, status, and creation timestamp.
Guardian Approval Loop (2 of 3 Required)
For each guardian (slot 0, 1, or 2), the user submits an approval request. The wallet-api fetches ceremony state, calls the guardian-attestor to generate a signed attestation, then submits the approval to the recovery-ceremony. The ceremony aggregates signatures and checks the 2-of-3 threshold.
Endpoint: POST /wallet/recovery/approve
The guardian-attestor receives the ceremony_id, old_credential_commitment_b64u, new_credential_id_b64u, created_at, and guardian_slot. It returns a guardian_pubkey_b64u and guardian_signature_b64u.
Time-Lock Wait
A mandatory delay period must elapse before finalization. This prevents immediate hostile takeover and gives the legitimate account owner time to react and cancel a fraudulent recovery. The ceremony blocks any finalization attempt until created_at + timelock_seconds has elapsed.
Monitor: GET /wallet/recovery/:ceremonyId
Mandatory delay: timelock_seconds (default 30s). Ceremony blocks finalization until created_at + timelock elapsed. User can monitor progress via GET endpoint.
Ceremony Finalization
The user or client calls finalize. The recovery-ceremony verifies that the time-lock has expired and that at least 2 guardian approvals have been recorded. If both conditions are met, a recovery_receipt is generated containing the new credential binding, cryptographically signed as proof of legitimate recovery.
Endpoint: POST /wallet/recovery/finalize
Checks: (1) timelock expired (created_at + timelock_seconds < now), (2) guardian approvals ≥ 2. Output: recovery_receipt with new credential binding.
Apply Binding Update
The wallet-api sends the recovery receipt to the ledger-service, which updates the account's authentication binding to the new credential. The user can now authenticate with their new device passkey. MPC key shares remain encrypted at rest and are untouched. A RECOVERY_COMPLETED event is published to Kafka.
Endpoint: POST /ledger-service/account/binding/update
Defense-in-depth protections at every stage of recovery.
2-of-3 Threshold
Prevents single guardian compromise from enabling unauthorized recovery. At least two independent guardians must approve.
Time-Lock Protection
Prevents instant hostile takeover and gives the legitimate account owner time to react and cancel a fraudulent recovery attempt.
Privacy-Preserving Hashing
Old credential commitment is hashed. Attestors never see the raw credential, maintaining privacy throughout the ceremony.
Ed25519 Guardian Signatures
Guardian attestor signs with its own Ed25519 key, producing independently verifiable attestations.
MPC Keys Untouched
MPC key shares are NOT exposed during recovery. Only the account authentication binding changes. The key shard itself is never moved or exposed.
Cryptographic Receipt
Recovery receipt is a cryptographically signed proof of legitimate recovery, providing an immutable audit trail.
Five services coordinate the recovery ceremony pipeline.
wallet-api :8002
User-facing API gateway. Orchestrates the recovery flow by coordinating between recovery-ceremony, guardian-attestor, and ledger-service.
recovery-ceremony :8130
Manages ceremony lifecycle - creation, guardian approval recording, threshold checking, time-lock enforcement, and receipt generation. Backed by PostgreSQL.
guardian-attestor :8140
Generates signed guardian attestations using Ed25519 keys. Each guardian slot produces an independently verifiable approval signature.
ledger-service :8001
Applies the new credential binding to the account on the JIL L1 ledger. The authentication binding update is the final step of recovery.
JIL L1 Ledger
Immutable ledger layer where the credential binding is persisted. Ensures the recovery is recorded on-chain with full auditability.
Two PostgreSQL tables store ceremony state and guardian approvals.
recovery_ceremonies
- id - UUID, primary key
- account_id - varchar
- old_credential_commitment - bytea (hash)
- new_credential_id - bytea
- status - enum (pending, finalized, cancelled)
- timelock_seconds - integer
- created_at - timestamptz
- finalized_at - timestamptz, nullable
recovery_approvals
- ceremony_id - UUID, FK to ceremonies
- guardian_slot - integer (0, 1, or 2)
- guardian_pubkey - bytea
- guardian_signature - bytea
- approved_at - timestamptz
Nine endpoints across four services manage the recovery ceremony lifecycle.
| Service | Endpoint | Method | Purpose |
|---|---|---|---|
| wallet-api | /wallet/recovery/start | POST | Initiate recovery ceremony |
| wallet-api | /wallet/recovery/approve | POST | Submit guardian approval |
| wallet-api | /wallet/recovery/finalize | POST | Finalize recovery + apply binding |
| wallet-api | /wallet/recovery/:id | GET | Check ceremony status |
| guardian-attestor | /v1/approve | POST | Generate guardian attestation |
| recovery-ceremony | /v1/recovery/start | POST | Create ceremony record |
| recovery-ceremony | /v1/recovery/approve | POST | Record guardian approval |
| recovery-ceremony | /v1/recovery/finalize | POST | Finalize + generate receipt |
| ledger-service | /account/binding/update | POST | Apply new credential binding |
Recovery scenarios and how MPC key shares remain protected.
Password Lost, Passkey Available
If the user loses their password but still has their device passkey, no recovery is needed. The passkey bypasses the password entirely.
Device Lost
If the user loses their device, guardian recovery replaces the passkey binding to a new device. The underlying MPC key shares are not affected.
MPC Shares Remain Safe
MPC 2-of-3 key shares remain safe: user shard is encrypted to passkey, server shard stays in HSM. Neither shard is accessed during recovery.
Binding Update Only
Recovery only changes which credential can unlock the user's key shard. The shard itself is never moved or exposed during the ceremony.
Self-sovereign account recovery without exposing private keys.
JIL Sovereign's guardian recovery ceremony ensures users can always regain access to their accounts while MPC key shares remain encrypted and untouched.