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

WebAuthn works locally, but not in production #345

Closed joshtblack closed 1 year ago

joshtblack commented 1 year ago

Hi there, I've setup WebAuthn and got it working great locally, so in preparation for pushing to prod, I changed the rpID and origin respectively. This works semi-okay, on production, registration of both passkeys (Macbook Touch ID in this instance) and security keys work. However, when I go to authenticate with a security key, I receive this error:

NotSupportedError: Unrecognized name.

from verifyAuthenticationResponse. If I attempt to login with a passkey, it works fine.

This is a non-issue on local, so I'm hoping you'd be able to shed some light onto what this error means?

Thank you!

MasterKale commented 1 year ago

I'll need to see some code. For now please show me how you're calling generateAuthenticationOptions() or startAuthentication() (it's unclear if you're using SimpleWebAuthn end-to-end, or only using one or the other.) Right now it sounds to me like this is an issue within the browser, before verifyAuthenticationResponse() ever gets called, so it's probably something about the options that are making it to the actual WebAuthn API call within startAuthentication().

joshtblack commented 1 year ago

Sure. Here's how I'm calling generateAuthenticationOptions():

You might be wondering why I'm adding the 'allowCredentials' in the response rather than the options itself - it's because for some reason if I add the exact same allowCredentials code in the options, the id value is always empty, adding it into the response itself is the only way I could get it to work. Maybe you could shed some light on that as well?


    const rpID =
        process.env.NODE_ENV === "development"
            ? "localhost"
            : "dashboard.file.glass";
    const userAuthenticators = user?.u2f?.authenticators;

    const options = generateAuthenticationOptions({
        timeout: 60000,
        userVerification: 'preferred',
        rpID,
    });

const response = {
        ...options,
        allowCredentials: userAuthenticators.map((authenticator: { credentialID: any, transports: any }) => ({
            id: authenticator.credentialID,
            type: 'public-key'
        })),
    }
    res.status(200).json(response);
joshtblack commented 1 year ago

I'll include the code snippet to startAuthentication as well:


const response = await axios.get("/api/user/account/u2f/authentication/generateAuthenticationOptions");
        let asseResp;
        asseResp = await startAuthentication(response.data);
MasterKale commented 1 year ago

You might be wondering why I'm adding the 'allowCredentials' in the response rather than the options itself - it's because for some reason if I add the exact same allowCredentials code in the options, the id value is always empty, adding it into the response itself is the only way I could get it to work. Maybe you could shed some light on that as well?

Based on the fact that your allowCredentials can be returned as JSON without any extra work, I'm guessing the type of id (authenticator.credentialID) is string. Is this correct? If so that's going to be why you can't pass them in as the allowCredentials argument for generateAuthenticationOptions() - the method expects id to be a Uint8Array (or a subclass of it like Node's Buffer.)

I confirmed it just now:

console.log(generateAuthenticationOptions({
  allowCredentials: [{
    id: 'E_Pko4wN1BXE23S0ftN3eQ' as any,
    type: 'public-key',
  }],
}));
// {
//   challenge: 'si_omE1UAfeQo5OZxc60dL1PybHZ5O1HD3AFlYwLtrw',
//   allowCredentials: [ { id: '', type: 'public-key' } ], // <-- See `id` is an empty string here
//   timeout: 60000,
//   userVerification: 'preferred',
//   extensions: undefined,
//   rpId: undefined
// }

I'll include the code snippet to startAuthentication as well:

Let's see both full values of response.data, the one for localhost and the one for production.

joshtblack commented 1 year ago

Sure.

Localhost:

{
"challenge": "2XMfA-ExsMCdUTaQBhp6NObQLqyTLJwFU43cbQFo3vM",
"allowCredentials": [
   {
     "id": "obwcOYa/mAykrxchp4vS/gM0DGEANmRiDQUdAJN+0Xzbn2BjcZJ+ECPMHug1Inp1",
     "type": "public-key"
   }
],
"timeout": 60000,
"userVerification": "preferred",
"rpId": "localhost"
}

And production:

{
"challenge": "CKUSx8nD06FtXg2q_T3yZYpbYs85ydorE2MUxs5TuHg",
"allowCredentials": [
   {
     "id": "zByoK93+eosQIwnR77pX69x6G9ggiXYlmKrawIK704nw4+gOHveabtuBxkx3g0zh",
     "type": "public-key"
   }
],
"timeout": 60000,
"userVerification": "preferred",
"rpId": "dashboard.file.glass"
}

I've also implemented a fix for the allowCredentials, it is now working as expected when included in 'options', however the "Unrecognized name." error still presents.

MasterKale commented 1 year ago

Bizarre, nothing appears to be wrong with how you're invoking WebAuthn. And if you're able to use a passkey with this same setup then I'm wondering if it's an authenticator issue.

However, when I go to authenticate with a security key, I receive this error:

What security key are you using for this?

joshtblack commented 1 year ago

It's quite odd, really. I'm using a Yubico 5 NFC & 5C NFC - same issue with both.

MasterKale commented 1 year ago

What's the RP ID you set during registration? Is it the same as the one you specify during authentication?

And this is interesting, when I searched for "unrecognized name" I found a lot of hits related to SSL issues...I wonder if this is somehow related. All I have left at this point is straws to grasp at.

https://duckduckgo.com/?q=webauthn+%22Unrecognized+name%22&t=iphone&ia=qa

joshtblack commented 1 year ago

What's the RP ID you set during registration? Is it the same as the one you specify during authentication?

Yeah, "rp":{"name":"Fileglass","id":"dashboard.file.glass"} is retrieved from generateRegistrationOptions, and rpId":"dashboard.file.glass" is retrieved from generateAuthenticationOptions. However I assume they're the same.

An SSL issue could be it, since it works on localhost - but my SSL configuration is handled by Vercel so I'm not sure how I'd go from there in the event that's what the issue is.

For now I've just enforced "internal" transports only, until I can figure out how to get security keys to work on prod, such a random issue!

MasterKale commented 1 year ago

Well, might as well ask, what browser are you testing in? Is that security key error consistently coming up in other browsers you've tried too?

joshtblack commented 1 year ago

I've tried in Arc (Chromium) & Safari on macOS + Firefox on Windows. Same issue unfortunately. 🙁

MasterKale commented 1 year ago

For want of an answer, I posted your problem to the fido-dev mailing list. Let's see if anyone has any insights: https://groups.google.com/a/fidoalliance.org/g/fido-dev/c/fQTxWcAU20Y

serianox commented 1 year ago

You can activate some debug logs on Windows (to get the CTAP message exchanged) and Chrome (to get the API call to WebAuthn and the detailed errors).

Yubico made a FAQ on this! https://support.yubico.com/hc/en-us/articles/4404763857042-How-to-collect-FIDO-WebAuthn-logs

Had I known this, I wouldn't have invested so much in my own debug tools. :D

serianox commented 1 year ago

Additionally, if you need to go deeper, you can install Wireshark and sniff USB HID or USB CCID coms.

joshtblack commented 1 year ago

You can activate some debug logs on Windows (to get the CTAP message exchanged) and Chrome (to get the API call to WebAuthn and the detailed errors).

Yubico made a FAQ on this! https://support.yubico.com/hc/en-us/articles/4404763857042-How-to-collect-FIDO-WebAuthn-logs

Had I known this, I wouldn't have invested so much in my own debug tools. :D

Thank you for this, I grabbed the logs during authentication with my Yubico security key(s) and it does look like an error occurs, however I was unable to find any information relating to this error.

[2023/02/09 09:42:37.841791] ctap2_device_operation.h:185 -> {1: {"id": h'138B4110FFD32D8D4840A2D83B57D3E2F5ACD84EB751161D519D8292733A9147CC979A786A76AACA7CFF430CB1C2C755', "type": "public-key"}, 2: h'BC692D97B40940EFC7065D9AA654E9B64CF3296A95B3680A4A8860E4CB7DA8A70500000004', 3: h'4DCC473DACDDF8FB558AE7C2BDE367DCE475BAC73616A7F4FF5ADC1BB6305231DD95325205F3711B48893C206A7C913183DAE860C43C3D7CE4162BEC10862E03', 4: {"id": h'34363231366131372D616561372D343837612D393836382D376635313066633237303966'}}

FIDODebug[2023/02/09 09:42:37.209295] ctap2_device_operation.h:87 <- 2 {1: "dashboard.file.glass", 2: h'98602BC3AB8B2670939D939ED12F2EDE63F2191C4664968E9743D0112BB507E5', 3: [{"id": h'138B4110FFD32D8D4840A2D83B57D3E2F5ACD84EB751161D519D8292733A9147CC979A786A76AACA7CFF430CB1C2C755', "type": "public-key"}, {"id": h'42ADC516DF93095AFC4B9BB0565D6BCF20E2277C8B66665D1524F0C585AC15EA', "type": "public-key"}], 6: h'09BEF9C8ABB34CEF831ECA3D4018CE854E5A0373035667C009869650C9338EF8', 7: 2}

FIDODebug[2023/02/09 09:42:37.194000] ctap2_device_operation.h:185 -> {2: h'24CA67621399E96375B643FA759C2797FD5C04AF8596BBE9359D61BB5ACACCEB143662C295F46F748265FECE9ABCCB99'}

FIDODebug[2023/02/09 09:42:37.108173] ctap2_device_operation.h:87 <- 6 {1: 2, 2: 5, 3: {1: 2, 3: -25, -1: 1, -2: h'D33A15D9C6A1965B1013611F5685226993A3CA0BE5E71841BA42941A59A35D1C', -3: h'2F4D302648760B05508FC3B43FA34BDE62164174A2BB067DDD20AA974F989C5E'}, 6: h'1C2DCC775070C3D5972055AEBB809E0CB23E99AAFD5DCA091CF54EB64E53CD9B'}

FIDODebug[2023/02/09 09:42:37.107831] ctap2_device_operation.h:185 -> {1: {1: 2, 3: -25, -1: 1, -2: h'56241A3C2A00A55D8053EFE29A6E933A21C2188D70FEC9EC756E9FDA24762661', -3: h'31A5D438E84D36E3B35A4F1808935FFD55A38F3BFE8B581AF027025B1DCD2789'}}

FIDODebug[2023/02/09 09:42:37.101218] ctap2_device_operation.h:87 <- 6 {1: 2, 2: 2}

FIDODebug[2023/02/09 09:42:35.523877] ctap2_device_operation.h:185 -> {3: 8}

FIDODebug[2023/02/09 09:42:35.519256] ctap2_device_operation.h:87 <- 6 {1: 2, 2: 1}

FIDODebug[2023/02/09 09:42:35.518022] ctap2_device_operation.h:136 -> (CTAP2 error code 49)

FIDODebug[2023/02/09 09:42:34.750293] ctap2_device_operation.h:87 <- 1 {1: h'E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', 2: {"id": ".dummy"}, 3: {"id": h'01', "name": "dummy"}, 4: [{"alg": -7, "type": "public-key"}], 8: h'', 9: 1}

FIDODebug[2023/02/09 09:42:34.750249] fido_device.cc:80 The device supports the CTAP2 protocol.

FIDODebug[2023/02/09 09:42:34.750234] device_response_converter.cc:288 Unexpected protocol version received.

FIDODebug[2023/02/09 09:42:34.750228] device_response_converter.cc:265 -> {1: ["U2F_V2", "FIDO_2_0", "FIDO_2_1_PRE"], 2: ["credProtect", "hmac-secret"], 3: h'2FC0579F811347EAB116BB5A8DB9202A', 4: {"rk": true, "up": true, "plat": false, "clientPin": true, "credentialMgmtPreview": true}, 5: 1200, 6: [2, 1], 7: 8, 8: 128, 9: ["nfc", "usb"], 10: [{"alg": -7, "type": "public-key"}, {"alg": -8, "type": "public-key"}], 13: 4, 14: 328707}

FIDODebug[2023/02/09 09:42:34.719872] fido_device.cc:49 Sending CTAP2 AuthenticatorGetInfo request to authenticator.

FIDODebug[2023/02/09 09:42:34.719531] android_accessory_discovery.cc:81 Android accessory discovery started

FIDOEvent[2023/02/09 09:42:34.719419] get_assertion_request_handler.cc:326 Starting GetAssertion flow

FIDODebug[2023/02/09 09:42:34.719218] chrome_authenticator_request_delegate.cc:726 Found 0 caBLEv2 devices
pascoej commented 1 year ago

CTAP2 error code 49

This looks like CTAP2_ERR_PIN_INVALID.

joshtblack commented 1 year ago

CTAP2 error code 49

This looks like CTAP2_ERR_PIN_INVALID.

Interesting. I've tried resetting the PIN a couple of times and it seems to do the same - any ideas?

MasterKale commented 1 year ago

@joshtblack If you're interested in continuing this along, can you download and install the YubiKey Manager application, run it, and then report the Firmware versions for your two keys? It should look something like this:

Screenshot 2023-02-08 at 10 01 11 PM

I can pass this info along to someone else who might be able to shed some light on what's going on.

nuno0529 commented 1 year ago

CTAP2 error code 49 This looks like CTAP2_ERR_PIN_INVALID.

Interesting. I've tried resetting the PIN a couple of times and it seems to do the same - any ideas?

Just answer for this CTAP2_ERR_PIN_INVALID in the context. The command comes with .dummy rp.id and uses for device selection purpose only. See step 1.3 of https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#sctn-makeCred-authnr-alg

joostd commented 1 year ago

@joshtblack Regarding the "unrecognized name" error message, that sounds like a problem with TLS Server Name Indication (SNI).

Does you code perform backend calls to dashboard.file.glass? That seems to be a vercel.com site requiring SNI as it is hosting different sites on the same IP:

$ echo HEAD / | openssl s_client -connect dashboard.file.glass:443  | openssl x509 -noout -subject
...
subject= /CN=zeit.co
$ echo HEAD / | openssl s_client -connect dashboard.file.glass:443 -servername dashboard.file.glass | openssl x509 -noout -subject
...subject= /CN=dashboard.file.glass

Now SNI is well-supported by browsers so this should not be an issue, unless perhaps there is some old proxy in between that terminates the TLS connection?

To rule out SNI issues: can you try running your backend code on a different server that does not require SNI? Perhaps running your localhost instance through ngrok or something similar?

Just a hunch - but probably easy to test.

joshtblack commented 1 year ago

@joshtblack If you're interested in continuing this along, can you download and install the YubiKey Manager application, run it, and then report the Firmware versions for your two keys? It should look something like this:

Screenshot 2023-02-08 at 10 01 11 PM

I can pass this info along to someone else who might be able to shed some light on what's going on.

Sure, both keys are on Firmware 5.4.3.

joshtblack commented 1 year ago

@joshtblack Regarding the "unrecognized name" error message, that sounds like a problem with TLS Server Name Indication (SNI).

Does you code perform backend calls to dashboard.file.glass? That seems to be a vercel.com site requiring SNI as it is hosting different sites on the same IP:

$ echo HEAD / | openssl s_client -connect dashboard.file.glass:443  | openssl x509 -noout -subject
...
subject= /CN=zeit.co
$ echo HEAD / | openssl s_client -connect dashboard.file.glass:443 -servername dashboard.file.glass | openssl x509 -noout -subject
...subject= /CN=dashboard.file.glass

Now SNI is well-supported by browsers so this should not be an issue, unless perhaps there is some old proxy in between that terminates the TLS connection?

To rule out SNI issues: can you try running your backend code on a different server that does not require SNI? Perhaps running your localhost instance through ngrok or something similar?

Just a hunch - but probably easy to test.

@joostd Well, interestingly enough - when running my localhost environment via ngrok, everything works perfectly with no error. Does this boil down to some kind of Vercel issue?

joostd commented 1 year ago

@joshtblack hard to tell without knowing more details on your setup. But this seems to support my theory of SNI being the issue.

If I understand correctly, a Vercel-hosted server is used in a backend-call from JavaScript in the browser, failing with a DOMException (the NotSupportedError). The embedded error message is "Unrecognized name", indicating the HTTPS request is done using a client not supporting SNI.

Can you tell us more about that client? Is it using a framework of some sort? Or is it going through a proxy that does not support SNI?

You can verify if the client (the component initiating the backend call) is using SNI to connect to the correct virtual host? This can be done using Wireshark (using a GUI) or with tshark (using a CLI) as follows:

# tshark -i1 -Y 'tls.handshake.extensions_server_name contains "dashboard.file.glass"'

(you may need to use a different interface number) If the client uses SNI, tshark will output something like:

12614  27.955638 192.168.178.34 ? 76.76.21.123 TLSv1 382 Client Hello

If there is no output when you get the UnsupportedError, the client is not using SNI and you will need to find something that does.

joshtblack commented 1 year ago

I'll look into SNI more tomorrow - though I'll provide some info;

It's Next.js with API routes for the WebAuthn. So on the same server essentially.

smaeda-ks commented 1 year ago

+1 to @joostd's comment. I think ngrok serves the right cert (wildcard SAN) even without SNI, which may also support that. And yes, Vercel can't support non-SNI clients.

But I would be surprised if that's actually the case, because then this client must be having a hard time in TLS with a lot of websites as well 🤔

FYI, our supported TLS versions and ciphers are mentioned here: https://vercel.com/docs/concepts/edge-network/encryption#supported-tls-versions

joshtblack commented 1 year ago

(you may need to use a different interface number) If the client uses SNI, tshark will output something like:

12614  27.955638 192.168.178.34 ? 76.76.21.123 TLSv1 382 Client Hello

If there is no output when you get the UnsupportedError, the client is not using SNI and you will need to find something that does.

I get a fairly similar output.

252   2.696173 192.168.1.155 → 76.76.21.123 TLSv1 583 Client Hello
smaeda-ks commented 1 year ago

@joshtblack what do you get if you run curl -svo /dev/null 'https://dashboard.file.glass/' from the same machine/network? Do you get any TLS errors? Could you please share the full output?

joshtblack commented 1 year ago

Sure, here's the full output:

*   Trying 76.76.21.61:443...
* Connected to dashboard.file.glass (76.76.21.61) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
} [325 bytes data]
* (304) (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* (304) (IN), TLS handshake, Unknown (8):
{ [15 bytes data]
* (304) (IN), TLS handshake, Certificate (11):
{ [4039 bytes data]
* (304) (IN), TLS handshake, CERT verify (15):
{ [264 bytes data]
* (304) (IN), TLS handshake, Finished (20):
{ [36 bytes data]
* (304) (OUT), TLS handshake, Finished (20):
} [36 bytes data]
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=dashboard.file.glass
*  start date: Jan 10 05:17:21 2023 GMT
*  expire date: Apr 10 05:17:20 2023 GMT
*  subjectAltName: host "dashboard.file.glass" matched cert's "dashboard.file.glass"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* h2h3 [:method: GET]
* h2h3 [:path: /]
* h2h3 [:scheme: https]
* h2h3 [:authority: dashboard.file.glass]
* h2h3 [user-agent: curl/7.86.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x13a813400)
> GET / HTTP/2
> Host: dashboard.file.glass
> user-agent: curl/7.86.0
> accept: */*
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200 
< accept-ranges: bytes
< access-control-allow-origin: *
< age: 0
< cache-control: public, max-age=0, must-revalidate
< content-disposition: inline
< content-type: text/html; charset=utf-8
< date: Fri, 10 Feb 2023 11:30:19 GMT
< etag: "cf8c5348289a4b7f6a290563a563fdee"
< server: Vercel
< strict-transport-security: max-age=63072000
< x-matched-path: /
< x-vercel-cache: HIT
< x-vercel-id: syd1:syd1::dwn42-1676028619104-5fb6dd075d13
< content-length: 3476
< 
{ [3476 bytes data]
* Connection #0 to host dashboard.file.glass left intact
MasterKale commented 1 year ago

@joshtblack Can you share the full JSON options you pass to startRegistration() for a given registration? I'm particularly curious what you specified for user.name and user.displayName, and if you experience this no matter which user you attempt registration and authentication with in production.

It's been suggested there might be some kind of overflow issue going on within the security key if either of those are too big. It's worth a look while you're getting help about the vercel part of your setup.

smaeda-ks commented 1 year ago

The curl output from @joshtblack above suggests that there seems to be no issue with the client's SNI support, as it's getting the right cert.

* Server certificate:
*  subject: CN=dashboard.file.glass
*  start date: Jan 10 05:17:21 2023 GMT
*  expire date: Apr 10 05:17:20 2023 GMT
*  subjectAltName: host "dashboard.file.glass" matched cert's "dashboard.file.glass"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.

https://www.ssllabs.com/ssltest/analyze.html?d=dashboard.file.glass&s=76.76.21.61&latest

Although someone asked us on Twitter to look into this, I don't see anything wrong with Vercel so far. I'll leave this thread for now, but please ping me if you believe there's an issue on Vercel's side.

MasterKale commented 1 year ago

Thank you for taking a look, @smaeda-ks (that was me who @'d vercel on Twitter). We appreciate you taking the time to try and shed light on this mystery 🙇

joostd commented 1 year ago

@smaeda-ks if there is a problem with SNI, it would be a problem with the TLS client. Vercel supports SNI just fine. As @joshtblack is hitting the exception even when SNI is being sent (as tshark shows), it may be caused by something different entirely.

Still strange that the issue doesn't occur when using other backends (only confirmed over ngrok so far).

smaeda-ks commented 1 year ago

Also @joshtblack, make sure you're not getting any runtime errors when testing this flow on your production Vercel app: https://vercel.com/docs/concepts/deployments/logs#function-logs

joshtblack commented 1 year ago

@joshtblack Can you share the full JSON options you pass to startRegistration() for a given registration? I'm particularly curious what you specified for user.name and user.displayName, and if you experience this no matter which user you attempt registration and authentication with in production.

It's been suggested there might be some kind of overflow issue going on within the security key if either of those are too big. It's worth a look while you're getting help about the vercel part of your setup.

Sure;

{
  challenge: 'vyN0fQR4v7220jEkBmU7BDeKTUTqIyYhcWqxStYAXS4',
  rp: { name: 'Fileglass', id: 'dashboard.file.glass' },
  user: {
    id: '46216a17-aea7-487a-9868-7f510fc2709f',
    name: 'noodles',
    displayName: 'noodles'
  },
  pubKeyCredParams: [
    { alg: -8, type: 'public-key' },
    { alg: -7, type: 'public-key' },
    { alg: -36, type: 'public-key' },
    { alg: -37, type: 'public-key' },
    { alg: -38, type: 'public-key' },
    { alg: -39, type: 'public-key' },
    { alg: -257, type: 'public-key' },
    { alg: -258, type: 'public-key' },
    { alg: -259, type: 'public-key' }
  ],
  timeout: 60000,
  attestation: 'none',
  excludeCredentials: [],
  authenticatorSelection: {
    residentKey: 'required',
    userVerification: 'preferred',
    requireResidentKey: true
  },
  extensions: { credProps: true }
}
joshtblack commented 1 year ago

Also @joshtblack, make sure you're not getting any runtime errors when testing this flow on your production Vercel app: https://vercel.com/docs/concepts/deployments/logs#function-logs

POST request to the verifyAuthenticationResponse endpoint isn't even showing up in Vercel function logs which is weird.

Nevermind, it does appear - there are just no errors other than the 400 that the "Unrecognized name." error causes.

hwhmeikle commented 1 year ago

@MasterKale We recently updated to the latest version and began seeing this error (security key worked for registration, but failed with Unrecognized name for authentication). I went back to the previous version we were on 5.4.5 and authentication works fine. This was all on localhost too.

MasterKale commented 1 year ago

@hwhmeikle Well that's a turn of events. Can you share the JSON authentication options you passed into startAuthentication(), one for each version you tested?

hwhmeikle commented 1 year ago

@MasterKale Sure thing:

5.4.5

{
  "challenge": "sBSPxrjxpVlRnvmZs0vGe2neHh545wofxYeGI-bFMPo",
  "allowCredentials": [
    {
      "id": "lmlJQE3DJ4LmBnqaHNrOaU_zvbFcsIbxI-8-Crw_YOe87TYeNGQaI8HRSbkTj1I4L5JTtxU5-TzlstUmQdjpzw",
      "type": "public-key"
    },
    {
      "id": "_P8foni6vdB4NksXXPzrLQ23tLj2KCdokzo0rZWwAbA",
      "type": "public-key"
    }
  ],
  "timeout": 60000
}

7.1.0

{
  "challenge": "IfWtZbNk8JnX3D6wYEtAGkh30ocdO9gvRB11-ufRFyU",
  "allowCredentials": [
    {
      "id": "8ZDbNy_6MWnxDfx7xTmwq_hyKIV11hl7nrEDmwe7MSI",
      "type": "public-key",
      "transports": [
        "internal"
      ]
    },
    {
      "id": "VRPpslZw0dq7diKOQup6RMZo6GVx7Rt7DdmkPQZJEczv9SqI0upR1HQYPHM4eXj15c5OXqPGiiKzshvhC3bfQcWd84DTMgFbFkf7wiIMYTeiwzjU2fjFzgcfaL-UG-lwWExlo1YEyidYtiPYuqnnpBTA-QPVXbwtLSCxpB_grPs",
      "type": "public-key",
      "transports": [
        "nfc",
        "usb"
      ]
    }
  ],
  "timeout": 60000,
  "userVerification": "preferred"
}
MasterKale commented 1 year ago

@hwhmeikle huh, the only difference is the transports. What happens if you remove those with 7.1.0?

hwhmeikle commented 1 year ago

@MasterKale Removed transports and the error still occurs: image image

MasterKale commented 1 year ago

@hwhmeikle What OS + version, and browser + version are you experiencing this with?

hwhmeikle commented 1 year ago

@MasterKale

OS: macOS Ventura 13.2 Browser: Version 1.48.158 Chromium: 110.0.5481.77 (Official Build) (arm64)](https://brave.com/latest/)

MasterKale commented 1 year ago

Can you follow the instructions mentioned earlier to capture FIDO logs from Chrom(ium-based Brave)?

https://github.com/MasterKale/SimpleWebAuthn/issues/345#issuecomment-1423113767

hwhmeikle commented 1 year ago

Sure thing

FIDODebug[15:58:07] -> {1: {"id": h'694D6C2FB4914FAF69CB73742812A743559C6B6AA89B41670024C138CCFB62B329BF5126FE2A98F0092091EF23DE9665', "type": "public-key"}, 2: h'49960DE5880E8C687434170F6476605B8FE4AEB9A28632C7995CF3BA831D9763050000001F', 3: h'E54EF6EDE345DF4803E55AA43D43080C036BB810604F82F9BD8F65CDFE11572D176745CB0F191E5872CB31EF370A17958A626E8700AD77BBAB43DAAEFD9BB400', 4: {"id": h'7573725F3132313232313234323332333435657733343132'}}

FIDODebug[15:58:05] <- 2 {1: "localhost", 2: h'1F84D4F88D0D6DEC6045EAEDDCAEB7E5185ABEF037EF5EC2178456CA69D3014D', 3: [{"id": h'694D6C2FB4914FAF69CB73742812A743559C6B6AA89B41670024C138CCFB62B329BF5126FE2A98F0092091EF23DE9665', "type": "public-key"}, {"id": h'F190DB372FFA3169F10DFC7BC539B0ABF872288575D6197B9EB1039B07BB3122', "type": "public-key"}], 6: h'52230892E24DF6D9C21F5068C91AB732B654A4D24A0CD2293F3C154203DCB2C7', 7: 2}

FIDODebug[15:58:05] -> {2: h'D55253BBAA1BA58558BC208F36BF08730D4C9D2D302C02D9C6AD2FCC5BBAD20437719278B61E548C83AB8B14B21F6300'}

FIDODebug[15:58:05] <- 6 {1: 2, 2: 5, 3: {1: 2, 3: -25, -1: 1, -2: h'AF4624EEBE5A2F07237B5D96C580DCBBF23C1199F9A5D5A83F2624AC90A7F18F', -3: h'5708F017153733353A876EA4CB5EDC66073141CE62228CC5654D6EC57FA0EED8'}, 6: h'BCD81629EE0F27FD7F8F251221C5E23A7282A36360CD32C7F120A75591F4D7FD'}

FIDODebug[15:58:05] -> {1: {1: 2, 3: -25, -1: 1, -2: h'AD7BC855A994672EF03312195D7D09035632651F04EB2D22A70505828A9A3FE7', -3: h'6B4BC2FD4334AF7A3D34867066CD394D8139F77E44110FAF615BC80353F43EF1'}}

FIDODebug[15:58:05] <- 6 {1: 2, 2: 2}

FIDODebug[15:58:02] -> {3: 8}

FIDODebug[15:58:02] <- 6 {1: 2, 2: 1}

FIDODebug[15:58:02] -> (CTAP2 error code 49)
MasterKale commented 1 year ago

That's the same error code as @joshtblack... 🤔

MasterKale commented 1 year ago

One possibility is that the security key is full of discoverable credentials, since "residentKey": "required" was being passed into registration. I filled up a security key with discoverable credentials...

Screenshot 2023-02-14 at 9 04 14 PM

But authentication still worked fine with this key. So that rules that out...

hwhmeikle commented 1 year ago

I experimented with setting the registration/authentication options to the same defaults as 5.4.5 and still got the same error.

MasterKale commented 1 year ago

I can't recreate this at all. I tried Brave, I tried Safari, I tried filling up a security key, I tried resetting my key to have no PIN but require UV during auth, nothing I can think of recreates this issue.

@hwhmeikle Is your site hosted on vercel too?

hwhmeikle commented 1 year ago

@MasterKale Yeah darn, this is gnarly. I'll do some more playing around. We are hosted on Vercel but I'm observing this on localhost.

MasterKale commented 1 year ago

@MasterKale Yeah darn, this is gnarly. I'll do some more playing around. We are hosted on Vercel but I'm observing this on localhost.

The fact that you're using localhost is interesting to me, but now there are too many variables to consider and so I must ask you to prepare a reproduction. If you can create a basic reproduction with a barebones version of whatever your set up is, that strips out everything to just the minimum code that can cause this, then I can try to run it on my end and see if it recreates the problem.

I experimented with setting the registration/authentication options to the same defaults as 5.4.5 and still got the same error.

Are you saying you're getting the error with v5.4.5 now too?