Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for abort signal #52

Merged
merged 1 commit into from
May 11, 2024

Conversation

JohnnyCrazy
Copy link
Contributor

Hi,

Adds support for passing a AbortSignal via the optional signal property. This can be used to cancel credential requests, like when using mediation: 'conditional'.

A react hook example:

useEffect(() => {
  const abortController = new AbortController();

  async function startDeviceAuthentication() {
    const authentication = await client.authenticate([], "...", {
      authenticatorType: 'auto',
      userVerification: 'required',
      timeout: 60000,
      mediation: 'conditional',
      signal: abortController.signal,
    });

    // ...
  }

  void startDeviceAuthentication();

  return () => {
    abortController.abort();
  };
}, []);

As we add a new optional parameter, this should be backwards compatible.

@dagnelies
Copy link
Collaborator

Thanks

@dagnelies dagnelies merged commit d1a4b6f into passwordless-id:main May 11, 2024
@JohnnyCrazy JohnnyCrazy deleted the abort-signal branch May 12, 2024 10:44
@dagnelies
Copy link
Collaborator

Hi, I merged this directly since it's backwards compatible ...but what's actually the use case for this abort signal?

@JohnnyCrazy
Copy link
Contributor Author

When adding support for conditional UI to a SPA (like react), the signal can be used to cancel the currently active client.authenticate call. They implemented conditional UI as a long running promise, which needs to be awaited on. If you don't cancel it when navigating away from the login, future credential get/create calls fail because there is still one in progress. This is not needed when the navigation destroys the page context.

@hjaber
Copy link

hjaber commented May 17, 2024

I would utilize the abort signal also.

I initially call client.authenticate() and if it fails/client rejects, I then call client.authenticate() with the the option mediation: 'conditional' to allow autocomplete on an <input />, but the previous client.authenticate() must be aborted prior to calling again

@dagnelies
Copy link
Collaborator

@JohnnyCrazy @hjaber Hi guys ...I got another dumb question. Since only chrome and safari support this passkeys conditional UI, how do you deal with other browsers? Do you simply ignore them, or do you have some fancy fallback?

@hjaber
Copy link

hjaber commented May 24, 2024

@JohnnyCrazy @hjaber Hi guys ...I got another dumb question. Since only chrome and safari support this passkeys conditional UI, how do you deal with other browsers? Do you simply ignore them, or do you have some fancy fallback?

I do my best to make a fancy fallback but I mentally ignore the other browsers since there are a lot of edge cases to cover.

I call authenticate() with a try/catch and if it catches, I then call it with mediation: 'conditonal' which provides autocomplete on the input.

@dagnelies
Copy link
Collaborator

shouldn't it be the other way round? Direct authentication is more widely supported than conditional one.

For example, with Firefox and conditional mediation, it will simply do nothing. It won't throw an error. You have to check PublicKeyCredential.isConditionalMediationAvailable() in order to know if this autofill functionality can be used. And if you do use it, you have to abord it before calling registration for example.

@dagnelies
Copy link
Collaborator

dagnelies commented May 24, 2024

Duh... PublicKeyCredential.isConditionalMediationAvailable() returns true for firefox ...but in reality it doesn't work 😆 (I tested right now)

@hjaber
Copy link

hjaber commented May 24, 2024

Apologies for the miscommunication!

My goal in implementing a fallback is primarily to enhance the UI/UX experience, not necessarily to broaden support for different authentication methods.

I do have an initial check that I did not mention to check if the client supports passkeys (isUserVerifyingPlatformAuthenticatorAvailable() or isConditionalMediationAvailable()). If not, I default to a magic link login.

If passkeys are supported, I then attempt direct authentication. However, due to the inherent advantages and disadvantages of this approach, I've included a fallback for mediation. If mediation isn't supported, the process falls back to a magic link login.

As you mentioned isConditionalMediationAvailable() returns true on firefox but doesn't work, my auth flow will still allow for a magic link login in this situation (since autocomplete won't popup on an input)

@dagnelies
Copy link
Collaborator

just wanted to clarify things to avoid potential readers being confused.

The conditional mediation is something you trigger when the page loads to "activate" the autocomplete on the input. If this passkeys autocomplete does not work (like on FF), the fallback could be to trigger authenticate(...) directly, without mediation.

A couple of additional details:

  • isUserVerifyingPlatformAuthenticatorAvailable() => even if false, you can still use USB sticks, scanning a QR code and all other roaming authenticators ...just not the local platform (or not with user verification). That said, I'm not aware of any platform/browser supporting WebAuthn and not being able to use the local platform with usre verification.
  • isConditionalMediationAvailable() => as we've seen, it's not reliable, at least currently

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants