Skip to content

Commit 04283a3

Browse files
committed
Use built in PublicKeyCredential methods
1 parent 830c9ce commit 04283a3

File tree

1 file changed

+22
-41
lines changed
  • packages/template-retail-react-app/app/components/passkey-registration-modal

1 file changed

+22
-41
lines changed

packages/template-retail-react-app/app/components/passkey-registration-modal/index.jsx

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -84,19 +84,6 @@ const PasskeyRegistrationModal = ({isOpen, onClose}) => {
8484
}
8585
}
8686

87-
/**
88-
* Convert base64url string to ArrayBuffer
89-
*/
90-
const base64UrlToArrayBuffer = (base64Url) => {
91-
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
92-
const binaryString = atob(base64)
93-
const bytes = new Uint8Array(binaryString.length)
94-
for (let i = 0; i < binaryString.length; i++) {
95-
bytes[i] = binaryString.charCodeAt(i)
96-
}
97-
return bytes.buffer
98-
}
99-
10087
/**
10188
* Convert ArrayBuffer to base64url string
10289
*/
@@ -123,21 +110,7 @@ const PasskeyRegistrationModal = ({isOpen, onClose}) => {
123110
})
124111

125112
// Step 2: Convert response to WebAuthn PublicKeyCredentialCreationOptions format
126-
const publicKey = {
127-
challenge: base64UrlToArrayBuffer(response.challenge),
128-
rp: {
129-
name: response.rp.name,
130-
id: response.rp.id
131-
},
132-
user: {
133-
...response.user,
134-
id: base64UrlToArrayBuffer(response.user.id)
135-
},
136-
pubKeyCredParams: response.pubKeyCredParams || [],
137-
authenticatorSelection: response.authenticatorSelection,
138-
timeout: response.timeout,
139-
attestation: response.attestation || 'none'
140-
}
113+
const publicKey = window.PublicKeyCredential.parseCreationOptionsFromJSON(response)
141114

142115
// Step 3: Call navigator.credentials.create()
143116
if (!navigator.credentials || !navigator.credentials.create) {
@@ -163,19 +136,27 @@ const PasskeyRegistrationModal = ({isOpen, onClose}) => {
163136
throw new Error('Failed to create credential: user cancelled or operation failed')
164137
}
165138

166-
// Step 4: Convert credential to JSON format
167-
const clientExtensionResults = credential.getClientExtensionResults?.() || {}
168-
const credentialJson = {
169-
type: credential.type,
170-
id: credential.id,
171-
rawId: arrayBufferToBase64Url(credential.rawId),
172-
response: {
173-
attestationObject: arrayBufferToBase64Url(
174-
credential.response.attestationObject
175-
),
176-
clientDataJSON: arrayBufferToBase64Url(credential.response.clientDataJSON)
177-
},
178-
...(Object.keys(clientExtensionResults).length > 0 && {clientExtensionResults})
139+
// Step 4: Convert credential to JSON format before sending to SLAS
140+
// https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential/toJSON
141+
let credentialJson
142+
try {
143+
credentialJson = credential.toJSON()
144+
} catch (error) {
145+
// Fallback to manual encoding if toJSON() fails
146+
// Some passkey providers (e.g., 1Password) may not support the toJSON() method and return an error
147+
const clientExtensionResults = credential.getClientExtensionResults?.() || {}
148+
credentialJson = {
149+
type: credential.type,
150+
id: credential.id,
151+
rawId: arrayBufferToBase64Url(credential.rawId),
152+
response: {
153+
attestationObject: arrayBufferToBase64Url(
154+
credential.response.attestationObject
155+
),
156+
clientDataJSON: arrayBufferToBase64Url(credential.response.clientDataJSON)
157+
},
158+
...(Object.keys(clientExtensionResults).length > 0 && {clientExtensionResults})
159+
}
179160
}
180161

181162
// Step 5: Finish WebAuthn registration

0 commit comments

Comments
 (0)