Skip to content

feat(passkey): Add DELETE /passkey/wraps/{credentialId} - #21165

Open
nshirley wants to merge 1 commit into
mainfrom
passkey-wraps-delete
Open

feat(passkey): Add DELETE /passkey/wraps/{credentialId}#21165
nshirley wants to merge 1 commit into
mainfrom
passkey-wraps-delete

Conversation

@nshirley

@nshirley nshirley commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Because:

  • A wrap the client can no longer unseal is permanent, leaving the passkey
    stuck without passwordless Sync.
  • Settings needs a per-passkey switch for passwordless sign-in.

This commit:

  • Adds DELETE /passkey/wraps/{credentialId} behind an mfa:passkey token,
    rate-limited as passkeyWrapsDelete.
  • Adds deletePasskeyWrap through the repository, manager, and service.
  • Reports a credential with no wrap as deleted: false, not 404.
  • Requires no credential binding, unlike the read and the write.
  • Adds deletePasskeyWrap to fxa-auth-client.

Comment thread packages/fxa-auth-server/test/remote/passkey_wraps.in.spec.ts
@nshirley
nshirley marked this pull request as ready for review September 8, 2026 18:17
@nshirley
nshirley requested a review from a team as a code owner September 8, 2026 18:17
Copilot AI balanced review requested due to automatic review settings September 8, 2026 18:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes passkey authorization and credential-management behavior, warranting final human security review.

Pull request overview

Adds authenticated deletion of individual passkey wrap envelopes without removing the underlying passkey.

Changes:

  • Adds the rate-limited DELETE endpoint and security event.
  • Implements account-scoped deletion across repository, manager, and service layers.
  • Adds auth-client support and comprehensive tests.
File summaries
File Description
packages/fxa-auth-server/test/remote/passkey_wraps.in.spec.ts Tests endpoint behavior and authorization.
packages/fxa-auth-server/lib/routes/passkey-wraps.ts Defines the DELETE route and handler.
packages/fxa-auth-server/lib/routes/passkey-wraps.spec.ts Tests routing, rate limiting, and auditing.
packages/fxa-auth-server/docs/swagger/passkeys-api.ts Documents the endpoint.
packages/fxa-auth-client/test/client.ts Tests client request and response handling.
packages/fxa-auth-client/lib/client.ts Exposes deletePasskeyWrap.
libs/accounts/passkey/src/lib/passkey.wrap.repository.ts Adds account-scoped database deletion.
libs/accounts/passkey/src/lib/passkey.wrap.repository.in.spec.ts Tests repository isolation and deletion.
libs/accounts/passkey/src/lib/passkey.service.ts Adds deletion orchestration and metrics.
libs/accounts/passkey/src/lib/passkey.service.spec.ts Tests service outcomes and failures.
libs/accounts/passkey/src/lib/passkey.manager.ts Connects service and repository layers.
Review details
  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/fxa-auth-server/docs/swagger/passkeys-api.ts
@nshirley
nshirley force-pushed the passkey-wraps-delete branch 2 times, most recently from 7bc20fb to 3aff787 Compare September 8, 2026 19:50
Comment thread packages/fxa-auth-server/test/remote/passkey_wraps.in.spec.ts
Comment thread packages/fxa-auth-server/lib/routes/passkey-wraps.ts
// wrap_retrieved restates passkey.authentication_success) or is a side effect
// they did not take (wrap_deleted rides the passkey-deletion cascade).
// wrap_retrieved restates passkey.authentication_success) or lands on every
// passwordless sign-in, at a volume that would crowd out the rest.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be a separate issue - but this filtering might make more sense on the backend.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I had replied already. but it was funny you mentioned this, I had logged this up right before you commented https://mozilla-hub.atlassian.net/browse/FXA-14492

Comment thread packages/fxa-auth-server/test/remote/passkey_wraps.in.spec.ts
'passkeyWrapsGet'
);

if (!isBoundTo(cid, credentialId)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved below to ensure token check is rate limited?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see the explanation above 👌

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yep, sorry, meant to add a comment. Something I found while reviewing all of the work so far and figured I could sneak it in here 😬

@nshirley
nshirley force-pushed the passkey-wraps-delete branch from 16aed8a to 0e215cd Compare September 9, 2026 16:32
@nshirley

nshirley commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Force push was to handle merge conflict and update with main

@bcolsson bcolsson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving but I'd consider adjusting the wording on one of the strings.

# A passkey is a sign-in method that replaces a password. This string is shown when a passkey that could unlock the user's synced browser data had that access turned off, leaving the passkey itself usable for signing in.
recent-activity-account-passkey-wrap-deleted = Passkey sync access removed
# A passkey is a sign-in method that replaces a password. This string is shown when an attempt to turn off a passkey's access to the user's synced browser data did not complete.
recent-activity-account-passkey-wrap-deletion-failure = Removing passkey sync access failed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might just be me but Passkey sync access removal failed sounds more natural.

@nshirley
nshirley force-pushed the passkey-wraps-delete branch from 0e215cd to 5589a38 Compare September 12, 2026 01:03
@nshirley

Copy link
Copy Markdown
Contributor Author

Force push was to address the string update

Because:
- A wrap the client can no longer unseal is permanent, leaving the passkey
  stuck without passwordless Sync.
- Settings needs a per-passkey switch for passwordless sign-in.
- POST and GET record their failures; a failed delete would have left no
  audit trail.

This commit:
- Adds DELETE /passkey/wraps/{credentialId} behind an mfa:passkey token,
  rate-limited as passkeyWrapsDelete, with no credential binding.
- Adds deletePasskeyWrap through the repository, manager, service, and
  fxa-auth-client.
- Reports a credential with no wrap as deleted: false, not 404.
- Records wrap_deleted and wrap_deletion_failure, both hidden from the
  settings activity list.
- Adds patch 198-199 for the wrap_deletion_failure event name.
@nshirley
nshirley force-pushed the passkey-wraps-delete branch from 5589a38 to 9d4f267 Compare September 12, 2026 01:17
@nshirley

Copy link
Copy Markdown
Contributor Author

force push was just updating with main

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.

4 participants