Bluesky is intentionally public infrastructure — they’ve been clear that E2EE isn’t on their roadmap because it conflicts with moderation and search. Fair enough. But sometimes you just want to talk to someone privately. Whisper is my answer: use your Bluesky identity to find each other, then talk directly peer-to-peer through Iroh, with no server ever seeing a message.

How It Works

Sign in with Bluesky OAuth. Whisper generates an Iroh endpoint ID and publishes it to your ATProto repo as a custom record (app.whisper.key/self). When you want to chat with someone, Whisper fetches their endpoint ID from their PDS and both browsers independently compute a shared gossip topic from your sorted DIDs. No handshake coordination needed — you both arrive at the same channel.

Messages travel over QUIC (encrypted by Iroh), directly between browsers via WebAssembly. If you’re behind a NAT, Iroh’s relay network forwards encrypted packets it can’t read. Media files get an extra layer of AES-GCM encryption via the Web Crypto API before touching any server, and those encrypted blobs expire after 24 hours.

The Design Decisions

  • Both users must be online. There’s no server-side queue. This is intentional — if messages don’t queue, they can’t be subpoenaed. The compose box literally hides when your contact is offline.
  • Ephemeral keys. Fresh every session. No persistent key material means a simpler threat model.
  • IndexedDB for local history. Messages survive page refreshes but live nowhere else. Last 200 per contact.
  • Bluesky is just the address book. ATProto handles identity and peer discovery. It never touches message content.

The Stack

The Iroh Rust library compiles to WASM and runs entirely in the browser. The server (Bun + Elysia) only handles OAuth sessions and temporary encrypted blob storage. The frontend is vanilla JS — no framework, no build step, 1,847 lines split into focused modules.

It’s a proof of concept that E2EE is possible in the ATProto ecosystem without fighting the protocol. Use it for what it’s good at (identity), use something else for what it’s not (private messaging).