feat(settings): add the passkey wrap creation hook - #21187
Closed
vpomerleau wants to merge 1 commit into
Closed
Conversation
vpomerleau
force-pushed
the
FXA-14425
branch
3 times, most recently
from
September 11, 2026 01:09
c325a8c to
384c932
Compare
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Same-tick calls can corrupt hook state because early flow results never set flow.inFlight.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 2
- Review effort level: Balanced
Because: - Passwordless Sync needs kB sealed to a passkey's PRF output before a wrap can be stored. - The wrap store is create-only, so a mis-sealed or duplicated envelope wedges the credential until the passkey is deleted. This commit: - Adds createPasskeyWrapFlow, sealing kB into a wrap envelope bound to the account and credential the mfa:passkey proof names, and usePasskeyWrapCreation as its React state wrapper. - Reopens the envelope before storing it, catching platform crypto that seals what it cannot unseal. - Refuses spent, zeroed or wrong-width key material, and holds a sealed envelope in a store shared across instances so a retry re-sends identical bytes. - Maps server errnos to distinct failure reasons and drops a rejected proof from the JWT cache. - Zeroes kB and the PRF output once sealed, on every path that reads them. Closes #FXA-14425
vpomerleau
force-pushed
the
FXA-14425
branch
from
September 11, 2026 16:24
384c932 to
ea83d68
Compare
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
A mismatched-key retry discards the only byte-identical envelope and can wedge a credential after an ambiguous successful POST.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 1
- Review effort level: Balanced
| 'passkey_not_found', | ||
| 'wrap_conflict', | ||
| 'feature_disabled', | ||
| 'key_changed', |
Contributor
Author
|
Working on a shorter version of this PR - will open as a new PR. |
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Because
the passkey is re-enrolled.
This pull request
lib/passkeys/wrap/:createPasskeyWrapFlowsealskBinto a wrap envelope andstores it under an
mfa:passkeyproof;usePasskeyWrapCreationwraps it in React state.sub/cidbefore touching keymaterial, so the sealing context always matches what the server files the wrap under.
material.
including after a remount — re-sends identical bytes.
JwtTokenCache.kBand the PRF output once sealed.Issue that this pull request solves
Closes: FXA-14425
Checklist
Put an
xin the boxes that applyHow to review (Optional)
wrap/interfaces.ts(the failure-reason union andresult types) and
wrap/creation.ts(the flow). The hook is a 60-line state wrapper.Tests and fixtures are ~65% of the diff.
interfaces.ts→creation.tstop to bottom →use-passkey-wrap-creation.ts→creation.test.ts, theretriesandproof claimsblocks.
envelope wedges the credential permanently, so three guards do the heavy lifting: the
reopen-before-store check, the held envelope shared across instances via
passkeyWrapStore, and thecid/subread from the proof before any key material istouched.
kB/prfOutzeroing on every path is the other thing worth tracing.Screenshots (Optional)
Please attach the screenshots of the changes made in case of change in user interface.
Other information (Optional)
Not exported from
lib/hooks/index.tsorlib/passkeys/index.ts: the flow pulls in theHPKE suite, which builds a
CipherSuiteat module scope. Consumers deep-importlib/passkeys/wrap, aspages/Signindoes withusePasskeySignIn.