1Password / passkey-rs

A framework for defining Webauthn Authenticators that support passkeys
Apache License 2.0
120 stars 17 forks source link

Error deserializing `PublicKeyCredential` from JsValue #48

Open Ben-Lichtman opened 1 week ago

Ben-Lichtman commented 1 week ago

Trying to implement webauthn on the browser, which includes deserializing the browser's response to the message into a passkey_types::webauthn::CreatedPublicKeyCredential / passkey_types::webauthn::PublicKeyCredential, however it seems that the raw_id field of PublicKeyCredential is allowed to be {} when returned from the browser, which causes the deserialization to return an error.

let promise = window()
  .navigator()
  .credentials()
  .create_with_options(&creation_options)
  .map_err(Error::JsError)?;

let cred_jsvalue = JsFuture::from(promise).await.map_err(Error::JsError)?;

let cred = web_sys::PublicKeyCredential::from(cred_jsvalue);

let cred = <JsValue as JsValueSerdeExt>::into_serde::<
passkey_types::webauthn::CreatedPublicKeyCredential,
>(&cred)
.unwrap();
panicked at app/src/webauthn.rs:82:6:
called `Result::unwrap()` on an `Err` value: Error("invalid type: map, expected A vector of bytes or a base46(url) encoded string", line: 1, column: 41)
Progdrasil commented 6 days ago

Hi @Ben-Lichtman, the issue here is the use of ArrayBuffer by the webauthn types which is readonly memory. When trying to serialize to JSON it will automatically "drop" the value and replace it with an empty object. To get around this you need to either re-map the array buffer to an array or a base64url string. OR remap it directly from the web_sys/js_sys types. Perhaps wasm_bindgen_serde could help with this but I haven't tested it.

I would like to one day build wasm dedicated library for the passkey crates, but thats a fairly heavy lift that I currently don't really have time for. We alway welcome contributions.

Ben-Lichtman commented 11 hours ago

@Progdrasil I'm a little confused - isn't the deserialization though JsValueSerdeExt (via gloo) designed to do exactly that (remap from the web_sys type into your PublicKeyCredential type)?

It would make sense to me that the answer would be to change the Deserialize implementation on Bytes to handle visit_map?

Please let me know if I'm misunderstanding.