Skip to main content

Overview

Emergency access lets you designate trusted contacts who can request read access to your vault if you become incapacitated, lose your master password, or are otherwise unavailable. The system enforces a configurable waiting period during which you can approve or deny the request. If neither action is taken before the timer expires, access is granted automatically. This is distinct from family vault recovery, which uses Shamir’s Secret Sharing. Emergency access uses a wrapped key model where the access key is pre-encrypted at invite time and released only after authorization.

How it works

Status lifecycle

StatusDescription
pending_inviteOwner sent invite, contact has not accepted yet
activeContact accepted the invitation, no access requested
access_requestedContact initiated an access request, waiting period running
access_grantedAccess approved (manually or by timeout), 24-hour retrieval window
access_deniedOwner explicitly denied the request
access_expiredThe 24-hour retrieval window has passed
revokedOwner permanently revoked the contact

Invite flow

1

Owner adds a trusted contact

The vault owner enters the contact’s email address and configures a waiting period (in hours). A wrapped_access_key and invite_salt are generated client-side and stored server-side. The invite token hash is computed for secure lookup.
2

Invite email sent

PassAgent sends an email containing a link to /emergency/{token}. The invite expires after 7 days if not accepted.
3

Contact accepts the invitation

The contact clicks the link, signs into their PassAgent account (or creates one), and clicks “Accept Invitation.” The server verifies the invite_token_hash, checks expiry, and transitions the status from pending_invite to active.
The contact cannot be the same user as the vault owner. The server explicitly prevents self-invitations to avoid accidental misuse.

Access request flow

1

Contact requests access

The trusted contact initiates an emergency access request via POST /api/vault/emergency/request. The record must be in active status.
2

Waiting period begins

The server computes grant_at = now + wait_hours and transitions the status to access_requested. The vault owner receives a notification.
3

Owner responds (or does not)

The owner can approve or deny the request via POST /api/vault/emergency/respond. If approved, the status moves to access_granted with a 24-hour retrieval window. If denied, the status becomes access_denied. If the owner takes no action and grant_at passes, access is granted automatically.
4

Contact retrieves the key

Once in access_granted status, the contact calls GET /api/vault/emergency/access?contact_id=<uuid> to retrieve the wrapped_access_key and invite_salt. These are used client-side to decrypt the vault.
The 24-hour retrieval window is enforced server-side. If the contact does not retrieve the key within 24 hours of approval, the status automatically transitions to access_expired on the next access attempt.

Key exchange

The wrapped access key model ensures the server never holds the vault’s decryption key in plaintext.
Owner's vault IKM

   ├─ HKDF-SHA256("passagent-enc-v3") ──► encKey

   └─ invite_salt + encKey ──► AES-256-GCM wrap ──► wrapped_access_key
                                                      (stored server-side)

On retrieval:
   wrapped_access_key + contact's derived key ──► unwrap ──► encKey ──► decrypt vault items
The invite_salt provides domain separation so each emergency contact relationship uses a unique wrapping context. The wrapped blob is opaque to the server.

Waiting periods

Best for close family members where you want fast access in a genuine emergency. The shorter window means less time to react if the request is unauthorized, but the owner still receives an immediate notification.
You can update the waiting period at any time via PATCH /api/vault/emergency/{id} without re-inviting the contact. This only affects future requests, not one already in progress.

Owner controls

Revoking a contact

The vault owner can permanently revoke an emergency contact at any time using DELETE /api/vault/emergency/{id}. This transitions the status to revoked regardless of the current state. A revoked contact cannot request access or be re-activated — a new invitation must be sent.

Updating wait hours

The owner can adjust the wait_hours value for any active contact. The change takes effect on the next access request. An in-progress request retains its original grant_at timestamp.

Rate limiting

All emergency access endpoints enforce rate limits to prevent abuse:
EndpointLimitWindow
Add contact5 requests60 seconds
Request access5 requests60 seconds
Respond (approve/deny)5 requests60 seconds
Accept invite5 requests60 seconds
Revoke contact5 requests60 seconds
Update wait hours5 requests60 seconds
Rate limits are enforced per user with a fail-closed policy — if the rate limiter is unavailable, the request is denied.

Audit logging

Every emergency access action is recorded in the audit log with full context:
ActionLogged metadata
emergency_contact.addContact email, wait hours
emergency_contact.acceptVault owner ID
emergency_access.requestVault owner ID, wait hours, grant_at
emergency_access.approveContact user ID, contact email
emergency_access.denyContact user ID, contact email
emergency_access.retrieve_keyVault owner ID
emergency_contact.revoke(none)
emergency_contact.updateNew wait hours

API endpoints

MethodEndpointDescription
GET/api/vault/emergencyList your emergency contacts (as owner and as contact)
POST/api/vault/emergencyAdd a new trusted contact
PATCH/api/vault/emergency/[id]Update wait hours for a contact (owner only)
DELETE/api/vault/emergency/[id]Revoke an emergency contact (owner only)
POST/api/vault/emergency/acceptAccept an emergency contact invitation
POST/api/vault/emergency/requestRequest emergency access to a vault
POST/api/vault/emergency/respondApprove or deny an access request (owner only)
GET/api/vault/emergency/accessRetrieve the wrapped access key after approval
Emergency access is a one-way mechanism: the contact receives read access to the owner’s vault. It does not grant the owner access to the contact’s vault, nor does it create a bidirectional trust relationship.