Skip to content

feat: add biometric unlock via Bitwarden desktop app#355

Draft
Chr1s70ph wants to merge 2 commits into
doy:mainfrom
Chr1s70ph:feat/biometric-unlock
Draft

feat: add biometric unlock via Bitwarden desktop app#355
Chr1s70ph wants to merge 2 commits into
doy:mainfrom
Chr1s70ph:feat/biometric-unlock

Conversation

@Chr1s70ph

@Chr1s70ph Chr1s70ph commented Jul 8, 2026

Copy link
Copy Markdown

Disclaimer: This was made in conjunction with AI. I don't have the necessary knowledge in Rust, Cryptography and how to implement such a feature safely. I have reviewed the Code manually and cant find any obvious shortcomings.
I also only verified the behavior for MacOS, since I don't have a Linux machine at hand. This should be properly reviewed by someone knowledgeable before this gets merged.

Add support for unlocking rbw via the Bitwarden desktop app's biometric prompt, using the same IPC protocol the official browser extension uses. When the config option is enabled, rbw-agent connects to the desktop app's browser-integration socket, performs an RSA handshake to establish a shared secret, and sends an encrypted unlockWithBiometricsForUser request. The desktop app shows the OS biometric prompt and returns the account's user key on success.

If the desktop app is unavailable or biometric unlock fails, rbw falls back to the existing master password / pinentry flow.

Key implementation details:

  • Messages are wrapped as LegacyMessageWrapper { appId, message } to match the desktop app's expected wire format
  • Encrypted messages are serialized as EncString objects (not plain strings) to match the browser extension's serialization
  • Both string and object EncString forms are accepted on incoming frames
  • wrongUserId and invalidateEncryption responses are handled explicitly
  • Broadcast frames from other clients are skipped during handshake
  • All sensitive material (RSA key, shared secret, user key) is zeroized

Add support for unlocking rbw via the Bitwarden desktop app's biometric
prompt, using the same IPC protocol the official browser extension uses.
When the  config option is enabled, rbw-agent connects
to the desktop app's browser-integration socket, performs an RSA
handshake to establish a shared secret, and sends an encrypted
unlockWithBiometricsForUser request. The desktop app shows the OS
biometric prompt and returns the account's user key on success.

If the desktop app is unavailable or biometric unlock fails, rbw falls
back to the existing master password / pinentry flow.

Key implementation details:
- Messages are wrapped as LegacyMessageWrapper { appId, message } to
  match the desktop app's expected wire format
- Encrypted messages are serialized as EncString objects (not plain
  strings) to match the browser extension's serialization
- Both string and object EncString forms are accepted on incoming frames
- wrongUserId and invalidateEncryption responses are handled explicitly
- Broadcast frames from other clients are skipped during handshake
- All sensitive material (RSA key, shared secret, user key) is zeroized
@Chr1s70ph
Chr1s70ph marked this pull request as draft July 8, 2026 12:52
@Chr1s70ph

Copy link
Copy Markdown
Author

For anybody wondering: I use this daily myself. So it's usable, I just don't know if its implemented correctly/what can be optimized.

But it works totally fine for day to day usage if anyone wants to try

Validate incoming ipc frames the way the browser extension does: filter
by appId (the desktop app broadcasts replies to all connected clients),
match response messageId to the request, and reject responses with
timestamps outside the 10s validity window. Zeroize the decrypted
shared secret on error paths and stop logging raw ipc frames.

Cache the established channel (socket + shared secret) in the agent and
pre-connect at startup, like the browser extension does, so the
biometric prompt appears immediately instead of paying for a new rsa
handshake on every unlock. A cancelled prompt no longer retries, and
the unlock timeout now matches the extension (60s).

Commit was made in assistance with AI
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant