MasterKale / SimpleWebAuthn

WebAuthn, Simplified. A collection of TypeScript-first libraries for simpler WebAuthn integration. Supports modern browsers, Node, Deno, and more.
https://simplewebauthn.dev
MIT License
1.62k stars 137 forks source link

StartAutentication throwing 'Cannot read properties of undefined (reading 'replace') at base64URLStringToBuffer' #576

Closed hapnan closed 5 months ago

hapnan commented 5 months ago

Describe the issue

After receiving the response from generateRegistrationOptions and I put it in startRegistration, it issued an error

TypeError: Cannot read properties of undefined (reading 'replace')
    at base64URLStringToBuffer (index.js:25:36)
    at startRegistration (index.js:198:20)
    at register (formreg.tsx:67:40)
    at async eval (index.esm.mjs:2254:17)

Reproduction Steps

I'm using nextjs(14.2.3) for everything from frontend and backend including @simplewebauthn/server to generate registration options and verify them.

Expected behavior

Can perform passkey registration normally

Code Samples + WebAuthn Options and Responses

Dependencies

JSON Respons From server

{
  "options": {
    "challenge": "yD2nSHcYH0P1wzsMpBfcq19dV99IeCTYzMOxuXRNNkI",
    "rp": {
      "name": "Absensi Dinus",
      "id": "localhost"
    },
    "user": {
      "id": "jm3OPxJgbyvRufWdr2rquxjy_mrhfzp3iikTHG-IrNY",
      "name": "A11.2017.10743@Hapnan Arsad Riski",
      "displayName": "Hapnan Arsad Riski"
    },
    "pubKeyCredParams": [
      {
        "alg": -8,
        "type": "public-key"
      },
      {
        "alg": -7,
        "type": "public-key"
      },
      {
        "alg": -257,
        "type": "public-key"
      }
    ],
    "timeout": 60000,
    "attestation": "none",
    "excludeCredentials": [],
    "authenticatorSelection": {
      "residentKey": "preferred",
      "userVerification": "preferred",
      "authenticatorAttachment": "cross-platform",
      "requireResidentKey": false
    },
    "extensions": {
      "credProps": true
    }
  }
}

startRegistration function

const resp = await fetch(
      `https://localhost:3000/api/registration?nim=${data.nim}`,
      {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
        },
      },
    );
    const respon =
      (await resp.json()) as PublicKeyCredentialCreationOptionsJSON;
    let attResp: RegistrationResponseJSON;
    try {
      attResp = await startRegistration(respon);
      console.log("Registration Response :", JSON.stringify(attResp));
    } catch (error) {
      if (error instanceof Error) {
        if (error.name == "InvalidStateError") {
          console.log(
            "Error: Authenticator was probably already registered by user",
          );
        } else {
          console.log(error);
        }
      }
      throw error;
    }

Additional context

MasterKale commented 5 months ago

Hello @hapnan, your JSON Respons From server has the options for startRegistration() nested one level deep, off an "options" property in the JSON object. Can you try calling startRegistration() like this instead and see if that fixes your problem?

Screenshot 2024-05-31 at 11 04 32 PM

// Pass in the `options` property instead
attResp = await startRegistration(respon.options);
hapnan commented 5 months ago

yes it is true that it was caused by the response server being nested one level deeper so I changed my response server to be more correct, thanks for helping, @MasterKale