Skip to content

feat: passkeys migration to PRF - #10310

Open
lwin-kyaw wants to merge 5 commits into
mainfrom
feat/passkey-migrate-prf
Open

lwin-kyaw wants to merge 5 commits into
mainfrom
feat/passkey-migrate-prf

Conversation

@lwin-kyaw

@lwin-kyaw lwin-kyaw commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a secure userHandle → PRF passkey migration flow.
  • Keep the existing passkey record active until replacement registration, PRF authentication, and vault-key re-wrapping succeed.
  • Add cancelPasskeyReplacement to remove an in-flight replacement and its linked authentication ceremony.
  • Keep replacement ceremonies retryable when password validation or vault-key export fails.

Changes

  • Added:
    • generatePasskeyReplacementRegistrationOptions
    • completePasskeyReplacement
    • cancelPasskeyReplacement
  • Added PRF-required validation and replacement source-record checks.
  • Added linked ceremony cleanup, expiry handling, and concurrency protection.
  • Refactored shared registration verification, key-derivation, record creation, and persistence logic.
  • Added documentation, changelog entries, messenger action types, and comprehensive tests.

Test plan

  • Test successful userHandle → PRF migration.
  • Test password and vault-key export failures remain retryable.
  • Test rollback when registration, authentication, PRF, or encryption fails.
  • Test stale and concurrent replacement handling.
  • Test ceremony cancellation, expiry, and linked authentication cleanup.
  • Run passkey-controller tests:
    yarn workspace @metamask/passkey-controller run jest --no-coverage src/PasskeyController.test.ts

References

JIRA

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

High Risk
Changes touch passkey enrollment, vault-key wrapping, and atomic record replacement—security-critical paths where a bug could lock users out or leave inconsistent state.

Overview
Adds a userHandle → PRF migration path in @metamask/passkey-controller so legacy enrolled passkeys can be upgraded without leaving the wallet unprotected mid-flow.

New API: generatePasskeyReplacementRegistrationOptions (PRF-only create() options, excludes the current credential), completePasskeyReplacement (verify registration + post-registration PRF auth, re-wrap the vault key, atomically swap the record), and cancelPasskeyReplacement (drop one in-flight replacement and its linked post-registration auth ceremony). The old record stays usable until completion succeeds.

Safety and ceremony behavior: PRF output is mandatory for migration (prf_required); stale or changed source records are rejected (replacement_source_changed, migration_not_required). Registration ceremonies carry isReplacement / sourceCredentialId; post-registration auth ceremonies link back via registrationChallenge, with cleanup on expiry, capacity eviction, and registration delete. Password or vault-key export failures happen before ceremony teardown so clients can retry the same WebAuthn responses. Enrollment logic is refactored into shared verify/derive/save helpers, with credential ID checks on authentication.

Docs, changelog, messenger action types, and broad tests cover success, rollback, concurrency, and cancellation.

Reviewed by Cursor Bugbot for commit c6cdff1. Bugbot is set up for automated code reviews on this repo. Configure here.

@lwin-kyaw
lwin-kyaw requested review from a team as code owners September 21, 2026 10:33
@lwin-kyaw
lwin-kyaw deployed to default-branch September 21, 2026 10:33 — with GitHub Actions Active

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7f62357. Configure here.

Comment thread packages/passkey-controller/src/PasskeyController.ts
@lwin-kyaw

Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-preview

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@10.0.1-preview-c6cdff1dd
@metamask-previews/accounts-controller@40.0.0-preview-c6cdff1dd
@metamask-previews/address-book-controller@8.0.0-preview-c6cdff1dd
@metamask-previews/ai-controllers@2.0.0-preview-c6cdff1dd
@metamask-previews/analytics-controller@3.1.0-preview-c6cdff1dd
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-c6cdff1dd
@metamask-previews/announcement-controller@9.0.0-preview-c6cdff1dd
@metamask-previews/app-metadata-controller@3.0.0-preview-c6cdff1dd
@metamask-previews/approval-controller@10.0.0-preview-c6cdff1dd
@metamask-previews/assets-controller@16.1.0-preview-c6cdff1dd
@metamask-previews/assets-controllers@112.0.2-preview-c6cdff1dd
@metamask-previews/authenticated-user-storage@4.0.0-preview-c6cdff1dd
@metamask-previews/base-controller@10.0.0-preview-c6cdff1dd
@metamask-previews/base-data-service@2.0.0-preview-c6cdff1dd
@metamask-previews/bitcoin-regtest-up@2.0.0-preview-c6cdff1dd
@metamask-previews/bridge-controller@81.2.0-preview-c6cdff1dd
@metamask-previews/bridge-status-controller@76.3.0-preview-c6cdff1dd
@metamask-previews/build-utils@4.0.0-preview-c6cdff1dd
@metamask-previews/chain-agnostic-permission@2.0.0-preview-c6cdff1dd
@metamask-previews/chomp-api-service@5.0.0-preview-c6cdff1dd
@metamask-previews/claims-controller@1.0.1-preview-c6cdff1dd
@metamask-previews/client-controller@2.0.0-preview-c6cdff1dd
@metamask-previews/client-utils@3.0.2-preview-c6cdff1dd
@metamask-previews/compliance-controller@3.0.0-preview-c6cdff1dd
@metamask-previews/composable-controller@13.0.0-preview-c6cdff1dd
@metamask-previews/config-registry-controller@4.0.0-preview-c6cdff1dd
@metamask-previews/connectivity-controller@1.0.0-preview-c6cdff1dd
@metamask-previews/controller-utils@13.0.0-preview-c6cdff1dd
@metamask-previews/core-backend@11.0.0-preview-c6cdff1dd
@metamask-previews/cryptography@0.0.0-preview-c6cdff1dd
@metamask-previews/delegation-controller@4.0.0-preview-c6cdff1dd
@metamask-previews/earn-controller@13.0.0-preview-c6cdff1dd
@metamask-previews/eip-5792-middleware@4.0.0-preview-c6cdff1dd
@metamask-previews/eip-7702-internal-rpc-middleware@1.0.0-preview-c6cdff1dd
@metamask-previews/eip1193-permission-middleware@3.0.0-preview-c6cdff1dd
@metamask-previews/eth-block-tracker@16.0.0-preview-c6cdff1dd
@metamask-previews/eth-json-rpc-middleware@25.0.0-preview-c6cdff1dd
@metamask-previews/eth-json-rpc-provider@7.0.0-preview-c6cdff1dd
@metamask-previews/foundryup@2.0.0-preview-c6cdff1dd
@metamask-previews/gas-fee-controller@27.0.0-preview-c6cdff1dd
@metamask-previews/gator-permissions-controller@6.0.0-preview-c6cdff1dd
@metamask-previews/geolocation-controller@2.0.0-preview-c6cdff1dd
@metamask-previews/java-tron-up@2.0.0-preview-c6cdff1dd
@metamask-previews/json-rpc-engine@11.0.0-preview-c6cdff1dd
@metamask-previews/json-rpc-middleware-stream@9.0.0-preview-c6cdff1dd
@metamask-previews/keyring-controller@28.0.0-preview-c6cdff1dd
@metamask-previews/kyc-controller@0.4.0-preview-c6cdff1dd
@metamask-previews/local-node-utils@2.0.0-preview-c6cdff1dd
@metamask-previews/logging-controller@10.0.0-preview-c6cdff1dd
@metamask-previews/message-manager@15.0.0-preview-c6cdff1dd
@metamask-previews/messenger@3.0.0-preview-c6cdff1dd
@metamask-previews/messenger-cli@1.0.0-preview-c6cdff1dd
@metamask-previews/money-account-api-data-service@1.0.0-preview-c6cdff1dd
@metamask-previews/money-account-balance-service@3.0.0-preview-c6cdff1dd
@metamask-previews/money-account-controller@2.0.0-preview-c6cdff1dd
@metamask-previews/money-account-upgrade-controller@5.0.0-preview-c6cdff1dd
@metamask-previews/money-account-utils@2.0.0-preview-c6cdff1dd
@metamask-previews/multichain-account-service@14.0.0-preview-c6cdff1dd
@metamask-previews/multichain-api-middleware@5.0.0-preview-c6cdff1dd
@metamask-previews/multichain-network-controller@4.0.0-preview-c6cdff1dd
@metamask-previews/multichain-transactions-controller@8.0.0-preview-c6cdff1dd
@metamask-previews/name-controller@10.0.0-preview-c6cdff1dd
@metamask-previews/network-connection-banner-controller@1.0.0-preview-c6cdff1dd
@metamask-previews/network-controller@37.0.0-preview-c6cdff1dd
@metamask-previews/network-enablement-controller@7.0.0-preview-c6cdff1dd
@metamask-previews/notification-services-controller@29.0.0-preview-c6cdff1dd
@metamask-previews/passkey-controller@4.0.0-preview-c6cdff1dd
@metamask-previews/permission-controller@14.0.0-preview-c6cdff1dd
@metamask-previews/permission-log-controller@6.0.0-preview-c6cdff1dd
@metamask-previews/perps-controller@17.2.0-preview-c6cdff1dd
@metamask-previews/phishing-controller@18.1.0-preview-c6cdff1dd
@metamask-previews/platform-api-docs@0.2.1-preview-c6cdff1dd
@metamask-previews/polling-controller@17.0.0-preview-c6cdff1dd
@metamask-previews/preferences-controller@24.0.0-preview-c6cdff1dd
@metamask-previews/profile-metrics-controller@5.1.0-preview-c6cdff1dd
@metamask-previews/profile-sync-controller@32.1.1-preview-c6cdff1dd
@metamask-previews/ramps-controller@23.0.0-preview-c6cdff1dd
@metamask-previews/rate-limit-controller@8.0.0-preview-c6cdff1dd
@metamask-previews/react-data-query@2.0.0-preview-c6cdff1dd
@metamask-previews/remote-feature-flag-controller@7.0.0-preview-c6cdff1dd
@metamask-previews/sample-controllers@6.0.0-preview-c6cdff1dd
@metamask-previews/seedless-onboarding-controller@11.0.0-preview-c6cdff1dd
@metamask-previews/selected-network-controller@27.0.0-preview-c6cdff1dd
@metamask-previews/sentinel-api-service@2.0.0-preview-c6cdff1dd
@metamask-previews/shield-controller@7.0.1-preview-c6cdff1dd
@metamask-previews/signature-controller@40.0.0-preview-c6cdff1dd
@metamask-previews/smart-transactions-controller@27.0.1-preview-c6cdff1dd
@metamask-previews/snap-account-service@3.0.0-preview-c6cdff1dd
@metamask-previews/social-controllers@3.0.1-preview-c6cdff1dd
@metamask-previews/solana-test-validator-up@2.0.0-preview-c6cdff1dd
@metamask-previews/stellar-quickstart-up@0.0.0-preview-c6cdff1dd
@metamask-previews/storage-service@2.0.0-preview-c6cdff1dd
@metamask-previews/subscription-controller@9.1.0-preview-c6cdff1dd
@metamask-previews/transaction-controller@70.1.0-preview-c6cdff1dd
@metamask-previews/transaction-pay-controller@29.0.0-preview-c6cdff1dd
@metamask-previews/user-operation-controller@42.0.0-preview-c6cdff1dd
@metamask-previews/utils@12.0.0-preview-c6cdff1dd
@metamask-previews/wallet@14.0.0-preview-c6cdff1dd
@metamask-previews/wallet-cli@0.0.0-preview-c6cdff1dd

This branch was successfully deployed

1 active (outdated) deployment
default-branch 7f623571 Deployed Sep 21, 2026 by lwin-kyaw via Determine whether this PR is a release PR #4295
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.

3 participants