4

After reading extensive documentation about the WebAuth API i'm unable to successfully enable platform authentication on iOS.
I've tried setting the Authenticator Attachment to both cross-platform and platform, they yielded consistent results apart from iOS:

╭────────────────┬───────────────────────┬────────────────────────────┬────────────────────────────┬───────────────────────────────────────────────╮
│   Attachment   │       Windows 10      │         Android 8          │       MacOS Catalina       │             iOS 13                            │
│                │       Edge/Chrome     │        Chrome/Opera        │        Chrome/Safari       │      Webkit(Everything else is this anyways)  │
╞════════════════╬═══════════════════════╬════════════════════════════╬════════════════════════════╬═══════════════════════════════════════════════╡
│ cross-platform ║        USB Key        │     USB/Bluetooth Key      │      USB/Bluetooth Key     │                 USB/Bluetooth Key             │
│ platform       ║  Fingerprint/Face/Pin │ Fingerprint/USB/Bluetooth  │         Fingerprint        │               "Insert security key"           │
└────────────────┴───────────────────────┴────────────────────────────┴────────────────────────────┴───────────────────────────────────────────────┘
Nick
  • 729
  • 8
  • 18

4 Answers4

4

On October 19, 2020, Apple posted an explanation of their take on WebAuthn: https://webkit.org/blog/11312/meet-face-id-and-touch-id-for-the-web/

FaceID and TouchID are supported starting with iOS 14 and macOS Big Sur. To make it work, for every allowCredentials entry that is a platform authenticator you need to add transport: ["internal"], otherwise it will continue prompting for a USB/NFC token.

In essence, this:

const publicKeyCredentialRequestOptions = {
    challenge: challengeBuffer,
    allowCredentials: [{
        id: 'credentialsIdentifierOne', // Windows Hello
        type: 'public-key'
    }, {
        id: 'credentialsIdentifierTwo', // iOS FaceID
        type: 'public-key'
    }],
    timeout: 60000
}

Becomes this:

const publicKeyCredentialRequestOptions = {
    challenge: challengeBuffer,
    allowCredentials: [{
        id: 'credentialsIdentifierOne', // Windows Hello
        type: 'public-key',
        transports: ["internal"]
    }, {
        id: 'credentialsIdentifierTwo', // iOS FaceID
        type: 'public-key',
        transports: ["internal"]
    }],
    timeout: 60000
}

Overall, this is in line with the specs and you should be able to retrieve the list of transports for an authenticator by calling .getTransports() on AuthenticatorResponse. This is not widely documented in tutorials and even less widely supported, so be wary:

When setting up cross-platform authenticators, the returned value will typically only contain the transport that was used and not all transports that the authenticator supports. For example, YubiKey 5 NFC will only return ["usb"] when used while plugged in.

So you should either avoid setting transports for these authenticators all together, or set them to all "non-internal" transports: ["usb", "nfc", "ble"].

As for calling .getTransports(), check if it is available (December 2020, Safari still doesn't have it), and if it is not, then fallback to appropriate transports based on whenever you are requesting a platform authenticator or a cross-platform authenticator.

Another very important point: if you are launching SFSafariWebView to handle this in your app, be it PWA, Cordova or native, it will unexpectedly fail. Reason? Apple decided that user activation (click/tap) is required before FaceID is even offered as an option to the user. What's worse is that you have no idea that the authentication is guaranteed to fail - iOS makes it seem like everything is running correctly and even prompts the user to plug in their authenticator, while knowing that no such authenticator exists (credentials ID points to FaceID that iOS knows of).

The solution to above problem is to add an extra step and interrupt the authentication flow by asking the user to press a button before invoking WebAuthn code.

Xeos
  • 5,975
  • 11
  • 50
  • 79
3

Unfortunately support on iOS is currently limited to external authenticators only. Full support on iOS really is the last thing blocking widespread adoption so fingers crossed iOS 14 will deliver the needed features.

It gets a brief mention in the iOS 13.3 release notes:

https://developer.apple.com/documentation/ios_ipados_release_notes/ios_ipados_13_3_release_notes

ETA this will be coming soon:

https://developer.apple.com/videos/play/wwdc2020/10670/

mackie
  • 4,996
  • 1
  • 17
  • 17
0

chrome will not support any extensions:

https://bugs.chromium.org/p/chromium/issues/detail?id=1097972

There is the request to chromium team for support WebAuth for iOS 13,14

https://bugs.chromium.org/p/chromium/issues/detail?id=1101804

Thang Le
  • 1,419
  • 1
  • 17
  • 25
0

For me WebAuthn from .Net was a complete encoding conversion nightmare! I finally got it to work however but then had issues with iOS. In the end the fix was a simple one in my case once I figured out what was going on in that both Mac and iOS did not like it when I set the AuthenticatorAttachment. Thus I ended up having to detect the OS with a function I got from here: getOS()

Then I coded it out as follows:

   var os = getOS();
   if (os == 'iOS' || os =='Mac OS') {
      credentialOptions.authenticatorSelection.authenticatorAttachment = undefined;
   }
Anthony Griggs
  • 1,469
  • 2
  • 17
  • 39