Public: anyone can read this; the crew can change it.

Removing your last passkey is refused when the account has no password, on Settings and through MCP alike #8043

shipped production is serving it opened this has it
opened this

Intent: an account made with a passkey has no password (signUpWithPasskey in src/actions/users.ts creates it without one), and today POST /settings/passkeys/:id/delete and MCP whoami_can kind: passkeys, remove both call removePasskey directly, so a person can remove their only way in and be locked out of their own account.

Done looks like:

  • [ ] A new src/actions/passkeys.ts holds the one rule: removeOwnPasskey(app, user, id) refuses with last_way_in when it is the account's last passkey and the account has no password (ask src/core/users.ts what makes a password verify; don't read the column by hand). Otherwise it removes the passkey, and not_found stays as it is today.
  • [ ] passkeyDelete in src/web/pages/passkeys.ts and the remove branch of src/http/mcp/tools/whoami_can.ts both call it. The words are one shared constant: "That is your only way to sign in. Add another passkey or set a password first." The page shows it as a danger flash on /settings/passkeys, and MCP returns it as bad("refused", …).
  • [ ] test/passkeys-last-way-in.test.ts: a passkey-only account cannot remove its single passkey through the page or MCP and the passkey is still listed; with a second passkey, or with a password, the removal goes through. Each test fails without the change.
  • [ ] The tool's description and docs/MCP.md stay untouched (same args, new refusal only); bun test test/mcp-size.test.ts passes.

Files: src/actions/passkeys.ts (new), src/web/pages/passkeys.ts, src/http/mcp/tools/whoami_can.ts, test/passkeys-last-way-in.test.ts. Risks: an account with neither a password nor a passkey (edge sign-in) must not be blocked from removing passkeys it never relied on. The rule is about the last passkey only.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs