Biometric login for web apps using WebAuthn
Login to your banking website without the hassle of passwords or two-factor authentication.
Sr. Director of Engineering
March 30, 2021
Seeing is believing
We recently released the ability to authenticate to a Bank or Credit Union on the Banno Platform using biometric authentication. Over 4 million US consumers now have the same quick access experience that our native iOS and Android applications have enjoyed for years.
In the financial services sector, we have traditionally authenticated first with a username and password and then some sort of out-of-band challenge (SMS one time password, authenticator app, etc). For biometric logins in our web apps we wanted to match the experience of our native apps: returning users could quickly get access to their application with only biometric authentication.
Biometric auth as the primary factor
We decided to recognize biometric authentication methods as a primary factor authentication that does not require any additional challenges. Enablement of biometric authentication for a user occurs in our native app after a user is already authenticated via other means.
Basically - anywhere a password can be used in our apps, biometric authentication should be considered a suitable replacement. This includes step-up authentication challenges inside the app.
FIDO security keys (tokens) as a second factor
We also plan to use WebAuthn to support FIDO security keys. These "tokens" will be recognized as a 2nd factor authentication and would replace SMS one time passwords and authenticator apps. In this case a user must present a valid security key after a username and password validation as the primary factor.
Making these use cases reality was more involved than it should have been.
While there are many tutorials online for how to use WebAuthn, most did not directly address our use case. The one use case that is firmly documented is using external FIDO security keys as a form of multi-factor authentication. Once you move beyond that, there’s a lot of learning to be done.
Thankfully this plight has been realized. The FIDO Alliance has started work on a “How to” document to help navigate the complexities.
Attachment: platform vs cross platform
You need to know the difference between platform and cross platform authenticators. A platform attachment means it is built into the hardware of the device itself – like the fingerprint readers on mobile phones. Cross-platform is a roaming authenticator like a FIDO USB security key or a mobile phone itself. Mapping to our use cases, platform authenticators serve as a primary authentication factor and cross-platform serve as secondary factors.
What does this even mean? It’s security so getting this wrong sounds dangerous. It turns out that a value of “none” is what you probably want (and is the default). Attestations tell you details about the type of authenticator used - like the brand name. What you probably don’t know is that asking for an attestation involves a 2nd permission prompt from the user. A Google engineer finally explained it to me: unless you are using WebAuthn for a very specific, non-public purpose, you don’t need or want attestation.
It’s built in to the browser, right?
WebAuthn is touted as “easy” because the browser did the heavy lifting. But some server api has to understand and validate both the registration requests and authentications. There are some really in-depth articles on how to do this, but “easy” is not a word I would use to describe this process. It’s best to find a library or server plugin to handle this for you. It’s not nearly as hard though when you forgo attestation. Parsing the attestation is where things get really complicated - so just avoid it.
Privacy vs security
One of the biggest benefits to WebAuthn is that it prevents phishing. A WebAuthn registration is strongly bound to a single domain and will not activate anywhere else. This alone should make it a high priority to enable for applications. However, with the use cases I outlined above, you probably won’t see this benefit using biometric authentication. Why not? Because anti-tracking concerns prevent it.
To match our native applications, the desire was to enter the username and then immediately prompt for biometric authentication if the device supported it and was registered. However due to privacy restrictions the browser cannot know if it has a valid registration. We ended up storing that a particular username was registered in the browser app storage (cookies, local storage or IndexedDB). But that means that anytime the browser loses this state, we don’t know whether to prompt the user for biometric auth or not. In that case, we fall back to the standard password prompt with a button to let the user manually trigger the WebAuthn challenge. If the user chooses to continue with the password prompt, additional authentication challenges are required.
The end result is that password authentication will continue to be seen as normal.
You might think why not just always prompt the user for biometric auth? Well the user experience in this
scenario is pretty bad:
It’s unfortunate this is the case and I can foresee several ways to address this. The Credential Management API allows a user to choose from a saved list of usernames and passwords, why couldn’t they choose from a list of registered users with WebAuthn as the primary factor? I suggested just this but it wasn’t accepted. It does finally look like the spec is moving in exactly this direction now finally with new proposals on conditional UIs to select credentials are being discussed.
For the time being, primary factor WebAuthn seems relegated to a convenience feature and not the strong anti-phishing protection I had hoped.
Moving the web forward
WebAuthn has succeeded in closing a gap between web applications and native apps. It allows a web application to offer the same convenient and secure access via biometric authentication.
In one way the web actually leaped beyond native apps. The ability to securely use on-device biometric prompts in native apps for step-up authentication has been missing. Prompting the user is easy, but how does the server know that the on-device prompt was legitimate? Now we just need both Android and iOS to build in WebAuthn support directly. There are open source libraries to help for now, but it is definitely not easy.
It’s unfortunate that the privacy restrictions prevent the security protections from being fully realized. Hopefully future changes to the specification that are already underway will address these shortcomings.