[Feature Request] Opt-in account recovery (social recovery / key escrow) β design doc for review
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 38
- Forks
- 23
- Avg merge
- 11m
- Merged PRs (30d)
- 4
Description
Hi Code PDX π β this comes from Shelter Now, the Portland nonprofit lined up to run alpha testing of PASS with 10β20 unhoused testers (participants are paid stipends). Our Lived Experience Council and Village Federation groups reviewed the document-locker concept, and their clearest, most urgent ask was: "what happens when I forget my password or lose my phone?" β because today the honest answer is "your documents are gone."
Below is a draft design doc for an opt-in account recovery layer. Nothing here weakens the default posture β a user who doesn't opt in keeps exactly today's behavior. We'd love maintainer feedback before anyone writes code; Shelter Now will run paid lived-experience review sessions on whatever design direction the maintainers prefer, and we're happy to discuss on Discord or at a meetup too. (Full disclosure: drafting was AI-assisted; the requirements come from the lived-experience sessions and the repo was read closely β file references below are to Development.)
Two sibling asks from the same sessions will follow as separate issues once this one has a direction: encrypted storage of passwords/critical info, and an opt-in self-assessment β service-navigation flow.
PASS Design Doc β Feature 1: Opt-in Account Recovery
Status: DRAFT for Code PDX + lived-experience review Β· Date: 2026-07-16
Origin: Shelter Now Lived Experience Council + Village Federation feedback sessions
Audience: Code PDX maintainers, Shelter Now program staff, alpha testers
1. The problem, in plain language
If you forget your PASS password or lose your phone, your documents are gone.
For most apps that's an annoyance. For someone sleeping outside, losing a birth
certificate or immigration paper again β this time inside the app that promised
to keep it safe β is catastrophic and destroys trust in the whole program.
Today PASS delegates identity entirely to the Solid pod provider. Signup
creates a Community Solid Server v7 account with an email + password
(src/components/Signup/podSignupHelpers/registerPod.js); login is standard
Solid OIDC (src/contexts/SessionContext.jsx). There is no recovery path in
PASS itself β a lost credential means the pod is unreachable β and the target
population often has no stable email for a provider-side reset either. A
repo-wide search finds no recovery, key-management, or crypto code; the closest
prior issue is #650 (password-mismatch UX at pod creation).
Goal: an opt-in recovery layer so that a person who loses their password
and/or device can get back into their documents with help from people/orgs they
chose in advance β without weakening the default posture for anyone who doesn't
opt in.
2. Who this is for (design constraints)
- Users on basic phones or borrowed devices; phone numbers and emails change often.
- Passwords are frequently forgotten or written down and lost.
- Many users are undocumented or fleeing abuse: a recovery path must never
become a way for an abuser, or a subpoena-happy third party, to quietly gain access. - Reading level ~6th grade; consent must be genuinely legible, not a wall of text.
- Old browsers/devices: recovery enrollment and use must work on low-end Android
and shared library terminals (Web Crypto API is the ceiling; no native apps). - Opt-in only. A user who declines keeps exactly today's behavior.
3. What "recovery" means in PASS's architecture
Two distinct things can be lost, and they need different mechanisms:
- The login credential (pod-provider password). Recovering this restores
access to the pod. - Any future encryption keys. Today PASS does not encrypt client-side
(pods are protected by WebACL only), so #1 is the whole problem. But
Feature 2 (encrypted credential storage) introduces a client-held key, and
any recovery design must not paint that future work into a corner.
This doc therefore designs recovery around a recovery secret: today it can
reset/re-bind the pod credential; later the same enrollment can escrow a key-
encryption key for Feature 2 data. One consent moment, one mental model.
4. Candidate schemes
Scheme A β Single-org escrow (Shelter Now holds a recovery key)
At enrollment, the client generates a recovery secret and hands one encrypted
copy to a designated org (e.g., Shelter Now). Recovery = walk into the org,
prove who you are to a caseworker (photo, in-person recognition β this
population usually is personally known to staff), caseworker MFA-authorizes a
release, user resets their credential.
- Pros: simplest to build and to explain ("Shelter Now can help me get back
in"). Matches how this population already recovers everything else (mail,
benefits) β through a trusted org. Works with zero user-held artifacts. - Cons: the org becomes a single point of compromise and a subpoena target;
a malicious or coerced insider could act alone. Custodial liability
concentrates on one nonprofit. - What the user must understand: "Shelter Now can help you get back in.
That also means Shelter Now could be forced to open your account. You can
turn this off any time."
Scheme B β 2-of-3 Shamir split across separated parties (recommended)
The recovery secret is split with Shamir's Secret Sharing (audited
shamir-secret-sharing lib, GF(256)) into three shares:
- Share 1 β the user: printed QR card (wallet-size, laminated), or stored
on-device for smartphone users. - Share 2 β the deployment operator (e.g., PASS instance database).
- Share 3 β a second, organizationally separate trust domain (e.g., Shelter
Now-administered vault service with capability-scoped release tokens β
design pattern and reference implementation already exist from Shelter Now's
locker work: separate project/account,PUT/GET/DELETEunder distinct
bearer material, release gated on caseworker MFA + an active time-boxed grant).
Any two shares reconstruct. Normal recovery paths:
-
User has their card β card + operator share (org helps, but one org alone can't act).
-
User lost everything β operator share + vault share, released only in a
caseworker-MFA'd, audited, time-boxed session (this is named escrow β the
two orgs together can act without the user, and the consent says so plainly). -
Pros: no single credential/insider/subpoena on one org yields the secret;
degrades gracefully (lost card β lockout); the same machinery later supports
Feature 2's key escrow. Every release is written to an append-only, hash-
chained audit log the user can view. -
Cons: most moving parts; requires two administratively separate parties
(deployment operator + vault org) and an ops runbook; the honest claim is
"the two orgs together could open this" β must be said out loud in consent. -
What the user must understand: "Three keys. You hold one. Two different
organizations each hold one. Any two together can help you get back in.
That means those two organizations acting together could also get in
without you β every use is recorded, and you can see the record."
Scheme C β Social recovery (trusted contacts / guardians)
User designates 2β3 trusted people (friend, family member, caseworker as
peers); K-of-N of them approve a recovery request (Bitwarden Emergency
Access-style state machine: request β waiting period with veto β release).
- Pros: most decentralized; no org custody or liability; waiting-period +
veto is a strong anti-coercion control. - Cons: poor population fit as the only mechanism β trusted contacts in
this community also lose phones/accounts, relationships churn, and an abuser
is often inside the social graph. Guardians need working devices/accounts.
Waiting periods conflict with urgent needs ("my housing appointment is today"). - Verdict: offer later as an additional guardian type inside Scheme B
(a trusted person can hold Share 1 instead of a card), not as the base.
5. Comparison
| A: Single-org escrow | B: 2-of-3 Shamir (rec.) | C: Social recovery | |
|---|---|---|---|
| Lost password + lost card/device | β recoverable | β recoverable (escrow path) | β οΈ only if guardians reachable |
| One compromised org/insider can act alone | β yes (fatal) | β no | β no |
| Subpoena resistance | β single target | β οΈ requires two orgs | β strong |
| Abuser-adjacent risk | low (org gatekeeps) | low (org gatekeeps + audit) | β high (abuser in graph) |
| Works with no user device/artifact | β | β | β |
| Build + ops complexity | low | medium-high | medium |
| Custodial liability | concentrated | shared, gated, audited | minimal |
| Plain-language explainability | easiest | moderate (tested phrasing above) | moderate |
Recommendation: Scheme B, with Scheme A as the degenerate deployment mode
(a small deployment may start with both non-user shares under one org β worse,
but honest if consent says so) and Scheme C folded in later as an alternate
Share-1 holder. Rationale: it is the only option that simultaneously survives
"user lost everything," resists single-org compromise/coercion, and reuses an
already-designed, reference-implemented pattern (Shelter Now escrow-vault
design: capability-scoped vault, MFA + grant-gated release, tamper-evident
audit, crypto-shred that purges all shares on account deletion).
6. Threat model (Scheme B)
| Threat | Mitigation |
|---|---|
| Stolen/coerced staff account | One share only; release needs MFA + active grant; audit |
| Operator DB breach | Share 2 alone is useless |
| Vault credential breach | Share 3 alone is useless; release/delete tokens separated |
| Both orgs collude / legal compulsion of both | Accepted, named risk β disclosed in consent; audit trail; user can opt out or shred |
| Abuser impersonates user at front desk | In-person identity check by staff who know the client + MFA + logged; optional per-user "require my card" flag disables the no-card path |
| Lost card | Escrow path; card reissue (old Share 1 invalidated by re-split) |
| User wants out | Opt-out = shred Shares 2+3 (idempotent, fail-stop, audited); account returns to unrecoverable-by-design |
| Reconstruction leakage | Combine only in volatile browser memory; zeroize; never logged/sent |
7. UX flow (plain language, to be tested with LEC/VF)
Enrollment (opt-in, at signup or any time):
- "If you forget your password, do you want help getting back in?" [Yes / No, I understand no one can recover it]
- Plain-language consent screen (target β€6th grade, translated, read-aloud
button): who holds what, what they can/can't do, that every use is recorded. - Print/save the card (Share 1). Skippable ("I can't keep a card safe") β
consent then names the two-org escrow path explicitly.
Recovery:
- User comes to a participating org. Staff verify identity (procedure doc, not code).
- Caseworker (MFA) opens a recovery session; grant is time-boxed.
- Card path: scan card + operator share β reset. No-card path: operator +
vault shares β reset. Either way the user sets a new password on the spot
and gets a new card; the event appears in their visible history.
8. Custodial liability (for org review before build)
- Written custodianship agreement between deployment operator and vault org:
release procedure, identity-verification standard, breach notification,
subpoena/warrant handling (notify user unless legally barred), insurance. - Data minimization: vault stores share bytes + opaque person ID only β no
names, no documents. - Retention: shares deleted on opt-out, account deletion, or N months of
program inactivity (policy TBD with counsel). - This section needs review by Shelter Now counsel and Code PDX before any code merges.
9. Interaction with Features 2 & 3
- Feature 2 (encrypted credentials store): recovered account β recovered
passwords. This is intentional and must be named in consent ("people who
help you recover could, together, reach your saved passwords too"). Optionally
Feature 2 supports a per-item "extra lock" excluded from recovery. - Feature 3 (assessment): no interaction; assessment data lives outside the
recovery secret's scope and is separately deletable.
10. Prototype plan (after design review)
src/utils/recovery/module: split/reconstruct via the audited
shamir-secret-sharingpackage, QR card render (reusereact-qr-code+
the existing QR pattern fromsrc/components/Profile/CreateQRCode.jsx),
zeroization tests. Plain JS + JSDoc to match the codebase (no TS migration).- Enrollment UI + consent capture behind a
VITE_ENABLE_RECOVERYenv flag
(matching the existingenv.templateconfig style), components under
src/components/Recovery/with desktop/mobile split and Vitest +
Testing Library behavior tests, per repo conventions. - Reference vault with capability-scoped endpoints (adapted from Shelter Now's
vaultClient.tsinterface contract) β in-memory for the prototype. - Caseworker recovery session demo on the dev CSS instance.
- Lived-experience testing script: can testers correctly answer "who can get
into your account?" after enrollment. That comprehension test is the merge gate.
11. Open questions for Code PDX
- Where should credential re-binding live? PASS already drives the CSS v7
account JSON API (registerPod.jsusespassword.create/
password.logincontrols); the same API surface can support a
recovery-gated password reset on CSS deployments. External OIDC providers
(opencommons.net,inrupt.com, β¦) can't participate β is recovery a
CSS-deployment-only feature at first? (We think yes.) - Is a small companion service (the Share-3 vault) acceptable alongside the
CSS instance incompose.yaml, or should Share 3 live in a second Solid
pod controlled by a different org? - Should the recovery secret double as the future key-encryption key if PASS
adds client-side encryption (see issue #259's verifiable-credentials
direction and the sharing-model issues #705/#342)? We designed for that but
want maintainer input. - Does Code PDX prefer this iterated as a GitHub issue thread, a Discussion,
or an RFC doc underdocs/? We're also happy to bring it to the Discord /
a Code PDX meetup β Shelter Now can coordinate paid lived-experience
testing sessions for whatever design lands.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up β it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading src/components/Signup/podSignupHelpers/registerPod.js and src/contexts/SessionContext.jsx to understand current signup and Solid OIDC login, then review the proposed recovery schemes and their operational constraints. Done means maintainers and the named stakeholders agree on a recovery design and scope before implementation begins.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- authentication, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100