FusionAuth / fusionauth-issues

FusionAuth issue submission project
https://fusionauth.io
90 stars 12 forks source link

Login with passkey breaks with some marketing instrumentation software #2480

Open bhalsey opened 1 year ago

bhalsey commented 1 year ago

Login with passkey breaks with some marketing instrumentation software

Description

When some marketing instrumentation is installed on login forms, Login with passkey no longer works.

Affects versions

Up to 1.47.1. Happens with Brave with shields down and Koala customer intent software installed.

Steps to reproduce

Steps to reproduce the behavior:

  1. Install Koala
  2. Have shields down if using Brave
  3. Go to Login with passkey
  4. Login doesn't work, see an error in Javascript console

Expected behavior

User should be prompted for passkey and then login.

Console logs

Uncaught TypeError: Cannot read properties of null (reading 'getAttribute')
    at FormHelper.buildInputElementFromEventSubmitterValue (FormHelper.js?version=1.47.1:20:36)
    at #handleFormSubmit (OAuth2WebAuthnLogin.js?version=1.47.1:39:28)
    at forms.ts:332:18

Platform

robotdan commented 1 year ago

The issue seems to be that another piece of software, in our case Koala, intercepts the form submit, and instead of allowing propagation to continue, it stops propagation and then submits the form via JavaScript.

However, when we make WebAuthN API calls, they need to be in the first party context. Most browsers will put up warnings to the end user if you try to open a WebAuthN prompt using JavaScript. It really needs to be the result of a user interaction.

Our best bet, may be to ensure our handler is called before Koala. We may be able to accomplish this by ensuring any 3rd party JS gets loaded last.

robotdan commented 1 year ago

~I seem to be able to fix this by just ensuring our WebAuthN js loads before Koala.~

Spoke too soon.

Koala looks to be binding the submit handler to the document, specifying capture: true.

A boolean value indicating that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree. If not specified, defaults to false.

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

We are binding the event to the form itself. If I understand the doc correctly, this means Koala will get their handler called first before the event bubbles (or doesn't) to the form element, at which point we would be invoked. This seems really aggressive, but I suppose that is how they guarantee they get invoked first.

robotdan commented 1 year ago

A potential fix - although this is really brute force.

  1. Bind our handler to the document, using capture: true.
    document.addEventListener('submit', this.#handleFormSubmit.bind(this), { capture: true, once: true })
  2. Stop immediate propagation in our handler. Add event.stopImmediatePropagation(); to the handler.
    event.stopImmediatePropagation();

So the reason this breaks is because Koala (or other similar marketing instrumentation) binds their submit handler to the document with capture: true. This tells the browser to call this handler before any handler bound to the element to which the event has not yet propagated.

So if we want to play this game, we need to also bind our handler to the document. However, unless we also keep their handler from getting called, this will still fail because their code will be invoked and cancel the browser prompt for the pass key.

So by adding event.stopImmediatePropagation() to our handler, we not only keep the event from bubbling, but we keep the browser from calling any other event handlers bound to the same element, in this case the document.

We could make a change like this knowing that if the order of events for the WebAuthn workflow are modified - it will likely not work at all. So this particular page, or any page that uses WebAuthn browser APIs are critical, and we may want to block anyone else from managing the capturing the submit event.

The downside is that we don't know if this breaks any other valid use cases.

The best current work around is to not load marketing instrumentation JavaScript on these themed WebAuthn pages.

robotdan commented 1 year ago

At a minimum, we should probably be more defensive and fail nicer, and possibly log something to the JavaScript console indicating something went wrong and it may be due to 3rd party JavaScript libraries on the page.