Skip to content

feat(sdk-core): send webauthnInfo with enterpriseId for MPC (v1+v2) user keychain#8974

Open
rajangarg047 wants to merge 1 commit into
masterfrom
rajangarg047/wcn-848-mpcv2-user-keychain-webauthninfo
Open

feat(sdk-core): send webauthnInfo with enterpriseId for MPC (v1+v2) user keychain#8974
rajangarg047 wants to merge 1 commit into
masterfrom
rajangarg047/wcn-848-mpcv2-user-keychain-webauthninfo

Conversation

@rajangarg047

@rajangarg047 rajangarg047 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

For MPC/TSS wallet creation, createMpc attached the user keychain's passkey by sending a bare webauthnDevices array (no enterpriseId) on POST /api/v2/:coin/key. The wallet-platform atomic key-creation endpoint only consumes webauthnInfo (a single object that includes enterpriseId, used to validate the PRF salt) and ignores webauthnDevices on input — so passkeys were never persisted for TSS/MPC user keychains (the keychain came back with no webauthnDevices and Wallet Settings showed no passkey).

This switches MPC user-keychain creation to send webauthnInfo { otpDeviceId, prfSalt, encryptedPrv, enterpriseId }, mirroring the onchain key-creation contract that already works. Applied across all four MPC keychain implementations (ECDSA + EdDSA, both MPCv1 and MPCv2), since createMpc dispatches by curve (getMPCAlgorithm()) and version.

Changes

  • ecdsaMPCv2.ts / eddsaMPCv2.ts and ecdsa.ts / eddsa.ts (MPCv1): thread the existing enterprise (a createKeychains param) down to the USER participant keychain; build webauthnInfo (with enterpriseId) instead of the deprecated webauthnDevices array. encryptionVersion continues to flow into the PRF-encrypted encryptedPrv.
  • iKeychains.ts: widen WebauthnInfo with optional enterpriseId (required by the atomic create endpoint; not needed on the PUT update path, which resolves enterprise from the wallet). This also lets the onchain client path drop its type-widening workaround.
  • Unit test asserting the MPCv2 user keychain POST /key body carries webauthnInfo w/ enterpriseId, the PRF-encrypted prv decrypts with the webauthn passphrase, webauthnDevices is not sent, and the backup keychain carries no passkey material.

Context

Testing

  • sdk-core builds/type-checks clean.
  • modules/bitgo ECDSA MPCv2 createKeychains suite passes (8 passing) including the new webauthnInfo test.

🤖 Generated with Claude Code

@rajangarg047 rajangarg047 requested review from a team as code owners June 9, 2026 17:16
@rajangarg047 rajangarg047 marked this pull request as draft June 9, 2026 17:16
@linear-code

linear-code Bot commented Jun 9, 2026

Copy link
Copy Markdown

WCN-848

@rajangarg047 rajangarg047 changed the title feat(sdk-core): send webauthnInfo with enterpriseId for MPCv2 user keychain feat(sdk-core): send webauthnInfo with enterpriseId for MPC (v1+v2) user keychain Jun 9, 2026
@rajangarg047 rajangarg047 force-pushed the rajangarg047/wcn-848-mpcv2-user-keychain-webauthninfo branch from c05a54a to 19fc785 Compare June 9, 2026 18:07
@rajangarg047 rajangarg047 marked this pull request as ready for review June 9, 2026 18:08
…hain

MPC/TSS wallet creation attached the user keychain's passkey by sending a
bare webauthnDevices array (no enterpriseId) on POST /api/v2/:coin/key. The
wallet-platform atomic key-creation endpoint only consumes webauthnInfo (a
single object including enterpriseId, used to validate the PRF salt) and
ignores webauthnDevices on input, so passkeys were never persisted for
TSS/MPC user keychains.

Switch MPC user-keychain creation to send webauthnInfo with enterpriseId,
mirroring the onchain key-creation contract. Applied across all four MPC
keychain implementations (ECDSA + EdDSA, MPCv1 + MPCv2), threading the
existing createKeychains enterprise param down to the USER participant, and
widen WebauthnInfo with optional enterpriseId.

Add unit tests asserting webauthnInfo (with enterpriseId) is sent on the
user keychain across all four MPC paths, that the deprecated webauthnDevices
array is not sent, and that the PRF-encrypted prv decrypts with the webauthn
passphrase.

WCN-848

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rajangarg047 rajangarg047 force-pushed the rajangarg047/wcn-848-mpcv2-user-keychain-webauthninfo branch from 19fc785 to 185c039 Compare June 9, 2026 19:49
@rajangarg047

Copy link
Copy Markdown
Contributor Author

@claude

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

Claude finished @rajangarg047's task —— View job


Code Review for PR #8974

I've completed a comprehensive review of the changes for adding webauthnInfo with enterpriseId to MPC user keychain creation.

Todo List:

  • Read repository guidelines from CLAUDE.md
  • Analyze the interface changes in iKeychains.ts
  • Review MPC implementation changes (ECDSA v1/v2, EdDSA v1/v2)
  • Examine test coverage and correctness
  • Check for security implications and best practices
  • Verify consistency across all 4 MPC implementations
  • Provide comprehensive review feedback

Summary

This PR successfully addresses the issue where passkeys were not persisted for TSS/MPC user keychains. The changes correctly switch from the deprecated webauthnDevices array to the webauthnInfo object (including enterpriseId) that the wallet-platform atomic key-creation endpoint actually consumes.

Detailed Review

✅ Interface Changes (iKeychains.ts)

The addition of optional enterpriseId to WebauthnInfo is well-documented and properly typed:

  • Clear JSDoc explaining when enterpriseId is required vs optional
  • Maintains backward compatibility as the field is optional
  • Removes the type-widening workaround mentioned in the PR description

✅ Implementation Consistency

All four MPC implementations are consistently updated:

  • ECDSA MPCv1: Lines 428-440 in ecdsa.ts:createParticipantKeychain
  • ECDSA MPCv2: Lines 439-454 in ecdsaMPCv2.ts:createParticipantKeychain
  • EdDSA MPCv1: Lines 205-219 in eddsa.ts:createUserKeychain
  • EdDSA MPCv2: Lines 283-298 in eddsaMPCv2.ts:createParticipantKeychain

Each implementation follows the same pattern:

  1. Only applies to USER keychains (not backup/bitgo)
  2. Requires enterprise parameter when webauthn is used
  3. Sends webauthnInfo with all required fields including enterpriseId
  4. Does NOT send deprecated webauthnDevices

✅ Security Best Practices

  • ✅ Proper validation: enterprise parameter is required when attaching webauthn devices
  • ✅ PRF-derived encryption: encryptedPrv uses the webauthn passphrase for encryption
  • ✅ Scope limitation: Only USER keychains get webauthn info (backup keychains remain clean)
  • ✅ No credential exposure: Private key material is properly encrypted before transmission

✅ Test Coverage

Excellent test coverage in ecdsaMPCv2/createKeychains.ts:182-242:

  • ✅ Verifies webauthnInfo is sent (not webauthnDevices)
  • ✅ Confirms enterpriseId is included in the request
  • ✅ Validates PRF-encrypted private key decryption
  • ✅ Ensures backup keychain has no webauthn material
  • ✅ Uses realistic test data and proper assertions

✅ Code Quality

  • Clean, consistent implementation across all MPC variants
  • Proper error handling with meaningful messages
  • Good separation of concerns
  • Follows existing code patterns and conventions
  • Thread safety maintained

Minor Observations

  1. Documentation: The JSDoc for WebauthnInfo.enterpriseId is excellent and clearly explains the use case differences between POST and PUT operations.

  2. Backward Compatibility: The changes maintain full backward compatibility since enterpriseId is optional and the deprecated webauthnDevices field is simply not sent (rather than being removed from the interface).

  3. Testing Strategy: The test properly captures the actual HTTP request bodies to verify the correct fields are being sent, which is the right level of testing for this change.

Recommendation

✅ APPROVE - This PR successfully fixes the passkey persistence issue with a clean, well-tested implementation. The changes are:

  • Technically sound and secure
  • Consistently applied across all MPC implementations
  • Properly tested with good coverage
  • Well-documented and maintainable
  • Backward compatible

The implementation correctly addresses the core issue: the wallet-platform endpoint consumes webauthnInfo (not webauthnDevices) and requires enterpriseId for PRF salt validation during atomic key creation.


Job run: https://github.com/BitGo/BitGoJS/actions/runs/12345
Branch: rajangarg047/wcn-848-mpcv2-user-keychain-webauthninfo

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