Skip to content

@W-20224220 Passkey login in auth modal and login page#3611

Merged
jeremy-jung1 merged 64 commits intofeature/webauthn-loginfrom
W-20224220-passkey-in-auth-modal
Feb 2, 2026
Merged

@W-20224220 Passkey login in auth modal and login page#3611
jeremy-jung1 merged 64 commits intofeature/webauthn-loginfrom
W-20224220-passkey-in-auth-modal

Conversation

@jeremy-jung1
Copy link
Collaborator

@jeremy-jung1 jeremy-jung1 commented Jan 27, 2026

Adding passkey login to the login modal and login page

Description

Types of Changes

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Documentation update
  • Breaking change (could cause existing functionality to not work as expected)
  • Other changes (non-breaking changes that does not fit any of the above)

Breaking changes include:

  • Removing a public function or component or prop
  • Adding a required argument to a function
  • Changing the data type of a function parameter or return value
  • Adding a new peer dependency to package.json

Changes

  • (change1) Added passkey login prompt to auth modal and login page

How to Test-Drive This PR

Checklists

General

  • Changes are covered by test cases
  • CHANGELOG.md updated with a short description of changes (not required for documentation updates)

Accessibility Compliance

You must check off all items in one of the follow two lists:

  • There are no changes to UI

or...

Localization

  • Changes include a UI text update in the Retail React App (which requires translation)

hajinsuha1 and others added 30 commits November 5, 2025 14:43
- Created CreatePasskeyModal component for registering new passkeys with custom nicknames
- Added useAccountCreatedToast hook to show success toast with passkey promotion after account creation
- Integrated passkey registration flow into auth modal, checkout confirmation, and registration pages
- Implemented initial WebAuthn registration API call to /oauth2/webauthn/register/authorize
- Added UI elements for passkey nickname input and registration button
- Update
- Renamed CreatePasskeyModal component to PasskeyRegistrationModal for clearer naming
- Renamed useAccountCreatedToast hook to usePasskeyRegistration to better reflect its purpose
- Refactored modal state management to pass props directly instead of wrapping in component
- Updated imports and references across auth, registration and checkout confirmation pages
- Simplified modal state object returned from usePasskeyRegistration hook
- Updated component
- Added two-step passkey registration flow with email verification code
- Implemented WebAuthn credential creation using browser's native API
- Added base64url encoding/decoding utilities for WebAuthn binary data handling
- Created verification code input with auto-submit on 8 digits
- Added resend code functionality for verification step
- Added state management to handle registration steps and form data
- Updated modal UI to show different
- Moved PasskeyRegistrationModal from auth/registration/checkout pages to account page for consistent user experience
- Added session storage flag 'newAccountCreated' to track when to show passkey registration prompt
- Simplified registration flow by removing duplicate passkey modal instances
- Updated auth flows to defer passkey registration until user reaches account page
- Removed unused passkey imports from auth-modal, registration,
- Replaced direct sessionStorage calls with utility functions (setSessionJSONItem, getSessionJSONItem, clearSessionJSONItem)
- Consolidated new account flag handling across auth modal, registration, checkout, and account pages
- Added temporary login trigger for passkey registration testing
- Updated all components to use consistent storage approach for newAccountCreated flag
…error handling

- Integrated finishWebauthnAuthentication to complete the passkey login flow.
- Improved error handling and logging for authentication processes.
- Added helper functions for base64url encoding/decoding to facilitate credential processing.
@jeremy-jung1 jeremy-jung1 changed the base branch from W-20224267-passkey-login-in-checkout to feature/webauthn-login January 28, 2026 02:11
@jeremy-jung1 jeremy-jung1 changed the base branch from feature/webauthn-login to W-20224267-passkey-login-in-checkout January 28, 2026 02:15
@jeremy-jung1 jeremy-jung1 added the skip changelog Skip the "Changelog Check" GitHub Actions step even if the Changelog.md files are not updated label Jan 28, 2026
Comment on lines +135 to +152
// Try WebAuthn first if enabled
if (isWebAuthnEnabled) {
console.log('WebAuthn enabled, trying to login with WebAuthn')
try {
await loginWithPasskey()
// If successful, close modal and navigate
onClose()
navigate('/account')
return
} catch (error) {
// Show error and stop - don't fall back to passwordless
form.setError('global', {
type: 'manual',
message: formatMessage(API_ERROR_MESSAGE)
})
return
}
}
Copy link
Collaborator

@hajinsuha1 hajinsuha1 Jan 29, 2026

Choose a reason for hiding this comment

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

@jeremy-jung1 I believe we agreed upon just having passkey be prompted automatically and not have it triggered via the button: https://salesforce.quip.com/3BbOAa3HFWrt#temp:C:CFGd921a1317f96456e88a1ba965

Also the latest best practices for passkey seem to be prompt automatically or triggering via autofill

const email = data.email
// Try WebAuthn first if enabled
if (isWebAuthnEnabled) {
console.log('WebAuthn enabled, trying to login with WebAuthn')
Copy link
Collaborator

Choose a reason for hiding this comment

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

should we remove this log?

}, [isRegistered, redirectPath])

useEffect(() => {
if (isWebAuthnEnabled) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

the loginWithPasskey hook actually already checks if passkey is enabled so we don't need to check before we call it

Comment on lines +233 to +236
loginWithPasskey().catch((error) => {
// Silently fail passkey login, user can still use other methods
console.log('Passkey login failed:', error)
})
Copy link
Collaborator

@hajinsuha1 hajinsuha1 Jan 29, 2026

Choose a reason for hiding this comment

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

this is okay for now as we'll address error messages as part of:
https://gus.lightning.force.com/lightning/r/ADM_Work__c/a07EE00002TfC8TYAV/view

Can we link the gus ticket so it doesn't get lost :)

Suggested change
loginWithPasskey().catch((error) => {
// Silently fail passkey login, user can still use other methods
console.log('Passkey login failed:', error)
})
loginWithPasskey().catch((error) => {
// TODO W-21056536: Add error message handling
})

loginWithPasskey()
} catch (error) {
// Silently fail
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

similar to above

Suggested change
}
} catch (error) {
// TODO W-21056536: Add error message handling

onClose,
isPasswordlessEnabled: !!passwordless?.enabled,
isSocialEnabled: !!social?.enabled,
isWebAuthnEnabled: !!passkey?.enabled,
Copy link
Collaborator

Choose a reason for hiding this comment

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

technically we don't need to pass isWebAuthnEnabled as loginWithPasskey handles the feature flag check

Comment on lines +33 to +48
jest.mock('@salesforce/commerce-sdk-react', () => {
const actual = jest.requireActual('@salesforce/commerce-sdk-react')
return {
...actual,
useAuthHelper: (helperType) => {
if (helperType === actual.AuthHelpers.StartWebauthnAuthentication) {
return {mutateAsync: mockStartWebauthnAuthentication}
}
if (helperType === actual.AuthHelpers.FinishWebauthnAuthentication) {
return {mutateAsync: mockFinishWebauthnAuthentication}
}
// Return actual for other helper types
return actual.useAuthHelper(helperType)
}
}
})
Copy link
Collaborator

Choose a reason for hiding this comment

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

one feedback i got in the feature/email-otp branch was to use msw for mocking the actual network call instead of mocking the commerce-sdk-react hook to be consistent with the other calls in this file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated!

Base automatically changed from W-20224267-passkey-login-in-checkout to feature/webauthn-login January 29, 2026 22:12
Copy link
Collaborator

@hajinsuha1 hajinsuha1 left a comment

Choose a reason for hiding this comment

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

LGTM!

@jeremy-jung1 jeremy-jung1 merged commit 0eb14be into feature/webauthn-login Feb 2, 2026
13 of 40 checks passed
@jeremy-jung1 jeremy-jung1 deleted the W-20224220-passkey-in-auth-modal branch February 2, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip changelog Skip the "Changelog Check" GitHub Actions step even if the Changelog.md files are not updated

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants