Jan 08 2019 06:36pm | | Share

Web Authentication API

By Pavlo Leheta


In this blog I discuss the Web Authentication API, a brand new standard for authentication on the web which promises to be more secure and easier to use. It is the future of web authentication and it’s very important for front-end developers to be acquainted with such technology.


Why We Need a Web Authentication API

Nowadays authentication heavily relies on passwords. People choose weak passwords and reuse them over multiple websites. It is hard to manage many passwords with today’s quickly growing number of online services and accounts for an average person. According to statistics calculated from Google Chrome’s password manager users, the average user reuses the same password 10 times out of 50, which is about 20%. One of the main concerns about password reuse, is that if it’s stolen it will unlock that user’s account on many other sites. But how do most passwords get stolen? The answer is phishing.


According to data from Google, 81% of hacking related account breaches last year leveraged weak or stolen passwords. Some studies show that in the period of one year about 2 billion usernames and passwords were stolen. 


To address this problem various multi-factor authentications have been implemented where additional ways of authentication, for example SMS verification codes, in conjunction with traditional password can be used. However, these implementations have no single standard and do not fully resolve this problem.


A Phishing Attack Example

Let’s take a look at a phishing attack against two-factor SMS authentication.  In figure 1, steps are as follows:

  1. User tries to authenticate themselves on a site which they believe is legitimate but in reality it’s run by con artists.
  2. The illegal site asks for a password which is provided by the user via a web form.
  3. The site sends that password to a legal site where the user actually intended to sign in.
  4. The legal site asks for the OTP (One Time Password) which in turn is being replayed by the illegal one.
  5. In the meantime, the legal site sends an SMS text to the user and provides the OTP.
  6. The unsuspicious user enters it into the illegal site, which in turn sends it back to the legal site making it “believe” it came from the actual user and gaining access to the user’s account.




An important reason phishing attacks work is the fact that the user is a human-being who can’t easily distinguish a legitimate website from a slightly changed fraudulent version. An attempt to solve this problem has been made with U2F (Universal second factor) security keys which eliminate a human factor by talking directly to a browser and verifying the legitimacy of a website’s URL. The reason why not everyone uses security keys today is because there hasn’t been a standard way of accessing such keys on the web that is available in all major browsers.


This has changed with the W3C’s Web Authentication initiative. Also known as WebAuthn, this is a new standard built into the browser which enables strong authentication by utilizing public key cryptography. SMS texts are no longer needed as it allows either passwordless authentication or secure second-factor authentication with various options. At the moment, according to, 64% of global users can take advantage of the API.


At last, users don’t have to remember dozens of complex passwords and be victims of phishing attacks, including those via SMS text messages. It’s not only secure but also much easier to use.

Let’s take a closer look.


What WebAuthn Is and How It Works

WebAuthn gives web applications browser-mediated access to authenticators – which can be a hardware token accessed over Bluetooth, USB, NFC or can be built into a platform such as fingerprint scanners or some other biometric devices. Authenticators can generate public/private key pairs and also gather user consent which can be granted with a simple tap, in case of security keys, or a successful fingerprint scan – in case of fingerprint readers, or by other method compatible with FIDO2 standard requirements. 


WebAuthn is an extension of the Credentials Management API that has been used in browsers for a while. It is implemented via the PublicKeyCredentials interface. The Credentials Management API already utilizes the PasswordCredential interface which provides information about username/password pair and the FederatedCredential interface – which provides information about credentials from a federated identity provider (an entity that is trusted by a website to correctly authenticate a user and provides an API for that).


Also these interfaces use the same base methods in the browser implementation: navigator.credential.create([options]) and navigator.credentials.get([options]) with different options. When create is used with the publicKey option, it allows creating new credentials for registering a new account or for associating a new public-private key pair with an existing account. Whenever get is used with the publicKey option – it uses an existing set of credentials to authenticate for either password-less login or as a two-factor authentication.  These two steps -- registration and authentication -- are explained below.



The Web Authentication API registration process looks like the following.




  1. Application makes initial registration request.
  2. Server or Relying Party sends a challenge, user and relying party informationto a JavaScript program. The parameters received from the server are passed to the create() method typically with little or no modification and returns a Promise that resolves to a PublicKeyCredential containing an AuthenticatorAttestationResponse. It is extremely critical that the challenge is a large buffer of random information generated on the server.
  3. Browser calls authenticatorMakeCredential() method on Authenticator- the browser validates the parameters and fills in any defaults, which become the AuthenticatorResponse.clientDataJSON. One of the most important parameters is the origin, which is recorded as part of the clientData so that the server can verify the origin later. The parameters to the create() call are passed to the authenticator, along with a SHA-256 hash of the clientDataJSON (only a hash is sent because the link to the authenticator may be a low-bandwidth NFC or Bluetooth link and the authenticator is just going to sign over the hash to ensure that it isn't tampered with).
  4. Authenticator Creates New Key Pair and Attestation - Before doing anything, the authenticator typically asks for some form of user verification. This could be entering a PIN, using a fingerprint to prove that the user is present and consenting to the registration or tapping a USB security key. After the user verification, the authenticator creates a new public-private key pair and safely stores the private key for future reference. The public key becomes part of the attestation, which the authenticator signs over with a private key that was burned into the authenticator during its manufacturing process and that has a certificate chain that can be validated back to a root of trust.
  5. Authenticator Returns Data to Browser - The new public key, a globally unique credential id, and other attestation data are returned to the browser where they become the attestationObject.
  6. Browser Creates Final Data, Application sends response to Server - The create() Promise resolves to a PublicKeyCredential object, which has a rawId that is the globally unique credential id along with a response that is the AuthenticatorAttestationResponseobject containing the clientDataJSON and attestationObject. The PublicKeyCredential is sent back to the server using any desired formatting and protocol.
  7. Server Validates and Finalizes Registration - Finally, the server is required to perform a series of checks to ensure that the registration was complete and not tampered with. These include:
    • Verifying that the challenge is the same as the challenge that was sent
    • Ensuring that the origin was the origin expected
    • Validating that the signature over the clientDataHash and the attestation using the certificate chain for that specific model of the authenticator


Assuming that the checks were successful, the server stores the new public key associated with the user's account for future use - for whenever the user desires to use the public key for authentication. 


Here is a sample code on how the registration looks like in JavaScript code.





After a user has successfully registered with WebAuthn, they can authenticate with the service. The process is very similar to the registration with a few differences explained below.




  1. Application requests authentication.
  2. Server or Relying Party sends only a challenge to a JavaScript program. 
  3. Browser calls authenticatorGetCredential() method on Authenticator
  4. Authenticator Creates an Assertion – The authenticator finds a credential for this service that matches the Relying Party ID and prompt a user to give a consent to authentication. When successful, the authenticator creates a new assertion by signing over the clientDataHash and authenticatorData with the private key generated for this particular account during the registration process.
  5. Authenticator Returns Data to Browser – the authenticator returns authenticatorData and assertion signature back to the browser.
  6. Browser Creates Final Data, Application sends response to Server - The browser resolves the Promise to a PublicKeyCredential with a PublicKeyCredential.response that contains the AuthenticatorAssertionResponse. It is up to the JavaScript application to transmit this data back to the server using any protocol and format of its choice.
  7. Server Validates and Finalizes Authentication – When server receives the result for its authentication request, it performs validation as follows:
  • Using the public key that was stored during the registration request to validate the signature by the authenticator.
  • Ensuring that the challenge that was signed by the authenticator matches the challenge that was generated by the server.
  • Checking if the Relying Party ID is the one expected for this service.


Here is a sample of how the authentication looks like in JavaScript code.




If you would like to see the WebAuthn in action, check the following links with a very nice demonstrations and explanations of the process with a debug terminal and details. You will need to have a USB security key to authenticate with.


How WebAuthn Prevents Phishing Attacks

Now that you have some knowledge about WebAuthn, let me tell you how WebAuthn prevents the phishing attacks I mentioned earlier. When the SHA-256 hash of the clientDataJSON is signed by the authenticator and sent to the server, that hash contains an “origin” parameter. The origin parameter identifies the domain of the trusted website (ex. and a phishing website cannot tamper with this data along the way because it won’t pass validation on the server. If a phishing site is proxying the requests, the expected origin won’t match and the authentication will fail.



I talked about the brand-new web platform API – the Web Authentication (WebAuthn) API which provides a standardized way of using strong authentication on the web. It uses public key cryptography instead of passwords or SMS texts and allows registering, and authenticating as well as second-factor authentication with web applications. WebAuthn resolves such significant security problems as phishing, data breaches, and attacks against SMS. It is also easier to use. The API provides browser-mediated access to authenticators, hardware tokens or built into platform modules.