Hi, I want to implement FIDO based biometric authentication in our app. I don't want to use passkeys because they are only compatible with iOS 16 and higher.
Is there a way to use it through the SFSafariViewController, a web view, ASWebAuthenticationSession or any another method?
It depends on what you're looking for. Do you want to use FIDO as an unphishable second factor to be added to a phishable first factor (e.g. a password)? Or are you looking to wholly remove phishability from accounts and use FIDO as a single factor? Do you want biometrics because "theft of an unlocked device" is one of the primary ways your accounts are getting compromised today, or because it checks a box about "another factor"? Does it have to be built in to the device, or do biometrics on an external security key meet these requirements?
If you don't need something built in to the device, security keys have been around since long before passkeys. Safari introduced support for them a few years ago (so they work in SFSafariViewController and ASWebAuthenticationSession) and we introduced native API for them in iOS 15. If you have a requirement that is literally "biometrics", you can enforce that only security keys with biometrics are used via attestation (though before you do so, you should consider the exact problem you're trying to solve with it). However, most existing security keys are meant to primarily be a second factor for high end needs, not a general consumer solution or sole factor for authentication.
If you do want something that's built in:
- If you want to actually remove phishability from an account, passkeys are the only existing solution that can achieve this. Passkeys are a sole factor replacement for password+standard 2FA (e.g. SMS, TOTP, email link, etc.) that is significantly stronger. Because they're backed up and synced, they're resilient to things like being forgotten or device loss, and can be the only factor for signing in, bringing that phishing resistance to the whole account. They also bring new features to FIDO, such as AutoFill support and cross-device cross-platform sign in, making discoverability and usability much easier and allowing them to live alongside passwords as people transition away from phishable factors. Safari and native apps share the same passkeys, so they can be used in SFSafariViewController, ASWebAuthenticationSession, or through the native API.
- Prior to passkeys, Safari had the legacy platform authenticator. Credentials here were meant for fast re-signin to the same website, but they had a lot of limitations. They were device bound, so not resilient to device loss and each account on each device had to be enrolled individually; they were invisible to the user, so there was nowhere to see or manage them; and they were ephemeral, so they could get deleted without warning and require the same device to be enrolled more than once for every account. Because they couldn't be a sole factor, accounts using this feature were still phishable, since other phishable factors are needed each time one sets up one of these credentials. These credentials also only lived in Safari (and by extension SFSafariViewController/ASWebAuthenticationSession); there was no native API support. Passkeys replaced this feature in iOS 16, bringing all of the above benefits.
- If your goal is not to remove phishability of accounts, but rather to perform a fast re-signin in an app on the same device, you can use the LocalAuthentication and Security frameworks to perform biometrics and create/use keys. These frameworks provide much lower level cryptographic primitives that you can use to build a custom auth stack to fit your needs, and have been available for years.
- If your goal is purely to cover as many users as possible, you can combine support for the above methods, as long as you're aware of the limitations. Using the WebAuthn API in Safari/SFSafariViewController/ASWebAuthenticationSession on a device prior to iOS 16 can result in a credential on a security key or using the legacy platform authenticator. That same code on a device on iOS 16 can result in a credential on a security key or using a passkey. You can distinguish what you got (and thus whether it can be a sole factor or additional factor) by checking the Backup State bits in the
authenticatorData
field of the response. And of course you can standard availability checks to see what native API is available before reaching out to the web.
Hopefully this helps :)