Skip to content

umbrella: Credible Exit ladder — identity portability across every level of sovereignty #448

Description

@melvincarvalho

"Credible exit means you can always leave — and take yourself with you. Not just your data. Your identity. Your reputation. Your relationships. Your history."

This issue tracks the Credible Exit ladder as it lands in JSS. Each rung is optional. Each rung is independently shippable. Users climb at their own pace; JSS supports them at every level.

The ladder

Level 6 ──▶ Hardware Wallet              Maximum sovereignty
Level 5 ──▶ Blocktrails                  Anchored, rotatable, recoverable
Level 4 ──▶ DID (Self-Sovereign)         You control the keys. Portable.
Level 3 ──▶ Passkeys                     Better security, still platform-bound
Level 2 ──▶ 2FA / OTP                    Second factor, still captive
Level 1 ──▶ OAuth / Social               "Login with X." Convenient cage
Level 0 ──▶ Password                     Where everyone starts

The journey is one-way upward and never destructive: same identity, same reputation, same followers, same history. Only the security improves and only the lock-in disappears.

Where JSS stands today

Level Status Where
0 — Password ✅ shipped /idp/register + --idp
1 — OAuth/Social ✅ shipped (in part) Solid-OIDC + --idp-issuer
2 — 2FA / OTP ⛔ not started
3 — Passkeys 🟡 issue open #78
4 — DID (claim identity) shipped mechanics #437 Phase 1 (--provision-keys) + Phase 2 (#443: VM in profile + did:nostr: controller)
4 — DID (claim handoff) ⛔ not started The "platform signs alice@cool.com → did:nostr:abc..." attestation flow
5 — Blocktrails (rotation + anchoring) ⛔ not started #437 Phase 3
6 — Hardware wallet ⛔ not started #437 Phase 4

The mechanics for Level 4 are already on disk — JSS 0.0.190+ provisions a Schnorr secp256k1 keypair and lands its public side in the WebID profile. The substrate exists. What's missing is the user-facing journey up the ladder, and the supporting infrastructure (recovery, anchoring, hardware) at the upper rungs.

Backup runs through every level

Backup isn't its own rung — it's the load-bearing companion at every level. As the user climbs, the backup payload grows:

Level What needs backing up
0–3 pod data (#353 — tar.gz export of <root>/<podName>/...)
4 + /private/privkey.jsonld (the secret) + signed handoff attestations
5 + key chain manifest (blocktrails) + Bitcoin anchor proofs
6 + hardware-wallet recovery seed (out-of-band, never on JSS)

Each backup tier is restorable end-to-end: encrypted snapshot + verifiable chain + provable anchors → the same Alice on a fresh server.

Phased plan

Grouped by realistic timeline. Each phase is a small, independently shippable issue + PR.

🟢 This week — already in flight

🟢 This month — small, well-scoped

  • feat: --provision-keys flag for pod creation (Schnorr/Nostr/CID v1.0 identity) #437 Phase 3 (start): --key-passphrase — wrap the on-disk secret with scrypt+aes-gcm. Operator picks a passphrase; secret on disk is no longer plaintext. Closes the "filesystem reads bypass WAC" hole from Phase 1 docs without needing hardware.
  • Identity claim handoff (new issue) — the L3→L4 step. Endpoint that returns a platform-signed attestation { from: alice@example.com, to: did:nostr:..., signed: example.com }. Single API call; user takes the JSON and walks. The Credible Exit moment.
  • feat: Add passkey (WebAuthn) authentication support #78 Passkeys — Level 3 step on the ladder. Bridges from Levels 0-1 toward Level 4 by reducing phishing without committing to keys-on-disk yet.
  • Backup hooks (new issue) — JSS exposes lifecycle hooks (onWrite, onAclChange, onKeyRotation) so adjacent CLIs (jss-backup, jss-anchor) can subscribe without bloating the server. Foundation for the borg / gitmark integration that follows.

🟡 Next 1-2 months — meaningful design

  • jss-backup companion CLI — wraps borg-style snapshots of the data dir + key + handoffs. Encrypted, dedup'd, push to remote. Restore = decrypt + verify chain. Lives outside JSS; consumes the lifecycle hooks above.
  • feat: --provision-keys flag for pod creation (Schnorr/Nostr/CID v1.0 identity) #437 Phase 3 (continue): BIP-39 seed-phrase derivation — operator can write down 12-24 words and recover the keypair without any disk file. Pairs with --key-passphrase as orthogonal recovery options.
  • Pod-as-git — opt-in mode where every LDP write auto-commits to a git repo in (or alongside) the data dir. Foundation for jss-anchor. Ships as --track flag in JSS; the anchoring lives in the companion.
  • Multi-user data export (Add self-service data export — download all my pod data #353 follow-up) — operator-side bulk export for "I'm shutting down this server, here's everyone's data." Different from the per-user export.

🟠 Months out — bigger pieces

  • jss-anchor companion — wraps gitmark. Anchors the pod-as-git history to Bitcoin via Nostr keys at configurable cadence. Verifiable from outside: "this commit existed at block H."
  • feat: --provision-keys flag for pod creation (Schnorr/Nostr/CID v1.0 identity) #437 Phase 4: Hardware wallet integration — Ledger / NIP-46 remote signers. Secret never touches JSS; signing requests proxied. Maximum sovereignty.
  • Key rotation flow (jss rotate-keys) — mints a new key chained from the old one via blocktrails. Updates WebID profile VM, NIP-05 mapping, did:nostr index in one transaction. Ships the L4 → L5 step end-to-end.
  • Encrypted-at-rest store — for environments where filesystem-level FDE isn't an option. Wraps every secret-tagged write transparently.

🔵 Future — when there's an ask

  • jss-restore — composes jss-backup + jss-anchor + key-chain verification end-to-end. Pulls a snapshot, proves it's the same identity at the same point-in-time, brings up a working pod on fresh infrastructure.
  • Cross-server pod migration — Solid pod portability spec. Hand a tar.gz to a different JSS, end up with the same WebID resolving to the new host. Big spec problem; defer until the ecosystem aligns.
  • Federated handoff verification — clients verify "alice@cool.com really did become did:nostr:abc..." without trusting JSS. Pure cryptographic verification of the handoff chain.
  • 2FA / OTP (Level 2) — TOTP, SMS fallback. Useful intermediate step on the ladder; not urgent given Passkeys (feat: Add passkey (WebAuthn) authentication support #78) likely lands first.

Cross-cutting principles

  • Ladder, not waterfall. Every level ships independently. Operators run JSS at any rung. Users climb when they're ready.
  • Same identity, every rung. Going from L4 to L5 doesn't mint a new identity — it adds an anchored chain to the existing one. No "migrate your followers" moment.
  • Backup tier follows identity tier. Don't backup more than the identity warrants. L0-3 = bytes. L4+ = bytes + key + handoffs. L5+ = + chain + anchors.
  • Companions, not core. Anchoring, encryption, hardware integration live in adjacent CLIs that consume JSS hooks. JSS stays focused on the protocol surface.
  • Honest about disk. A key on disk is a key on disk. We document filesystem-level threats (FDE, OS keyring, restrictive umask) at every level until L6 takes the secret out of disk entirely.

Out of scope for this umbrella

  • The financial / business side of the Credible Exit framing (platform competition dynamics, regulatory positioning) — useful framing but JSS is the substrate, not the policy argument.
  • The reputation-portability problem (followers, social graph) — distinct from identity portability; happens upstream in the apps that use JSS pods.
  • Cross-platform attestation standards — the L3→L4 handoff format will likely emerge from the broader DID community; JSS implements whatever wins.

Tracking

Phase Issue Status
L0–3 backup MVP #353 open
L3 Passkeys #78 open
L4 mechanics #437 Phase 1+2 shipped
L4 handoff (to file)
L5 wrap-on-disk (to file), slot of #437 Phase 3
L5 BIP-39 (to file), slot of #437 Phase 3
L5 pod-as-git (to file)
L5 backup hooks (to file)
L5 anchored backup (to file, companion)
L6 hardware wallet (to file), #437 Phase 4
L6 rotation (to file)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions