Enable TouchID and Windows Hello authentication for your site. Introduction to WebAuthn: How it works and how to implement it.

What is WebAuthn?

The Web Authentication API is an Authentication specification that allows websites to authenticate users using built-in authenticators (such as Apple TouchID and Windows Hello) or using security keys (such as Yubikey).

** It uses public key encryption technology instead of password. ** When a user registers, a public-private key pair is generated for the account. The private key is stored securely on the user’s device, while the public key is sent to the server. The server can then use the private key to ask the user’s device to sign a “challenge” to authenticate the user.

To WebAuthn registered

During registration, websites usually ask users to enter a username and password. With WebAuthn, the Web site generates a pair of public and private keys, sends the public key to the server, and stores the private key securely on the user’s device.

Log in using WebAuthn

During login, the site usually checks to see if the user has provided the correct username and password. With WebAuthn, the site sends a challenge and checks to see if the browser can sign the query using the private key stored on the user’s device.

Pure JavaScript implementation

To learn more about WebAuthn, here’s an in-depth explanation of how to implement WebAuthn in pure JavaScript. See Apple’s guide on WWDC20.

registered

Step 1: Your site asks the server to register WebAuthn.

The user is asked to enter some identifier (username, E-mail, and so on). Then, send a request to your server to register a new WebAuthn credential.

Step 2: The server specifies some options to create a new key pair.

Server specifies a PublicKeyCredentialCreationOptions object, the object contains the creation of a new PublicKeyCredential (key pair) some of the required and optional fields.

const optionsFromServer = {
    "challenge": "random_string".// Needs to be converted to ArrayBuffer
    "rp": {  					  // My website information
      "name": "My Website"."id": "mywebsite.com"
    },
    "user": {                     // User information
      "name": "[email protected]"."displayName": "Anthony"."id": "USER_ID_12345678910" // Needs to be converted to ArrayBuffer
    },
    "pubKeyCredParams": [{"type": "public-key"."alg": -7				  // Accept the algorithm}]."authenticatorSelection": {
    	authenticatorAttachment: "platform",},"timeout": 60000              // in milliseconds
};
Copy the code
  • rp: Specifies the dependent party’s information, the site the user is registered/logged into. If the user is registered with your site, then your site is a dependent party.
  • id: Indicates the domain name of the host, excluding the protocol and port. For example, if the source of the RP isLogin.example.com: 1337, then idislogin.example.comexample.comRather thanm.login.example.com.
  • pubKeyCredParams: Which public key types are acceptable to the server.
  • alg: a number that describes the algorithm accepted by the server and is in the COSE registryCOSE algorithmAre described below. For example, -7 is used for the ES256 algorithm.
  • authenticatorSelection: (Optional) Restrict the validator to platform or cross-platform. useplatformAllow authenticators like Windows Hello or TouchID. usecross-platformAllow authenticators such as Yubikey.

Step 3: On the front end, create a new key pair using options.

Using creationOptions we can tell the browser to generate a new key pair.

// Make sure you have converted strings to ArrayBuffer
// As described above
const credential = await navigator.credentials.create({
    publicKey: optionsFromServer 
});
Copy the code

The returned credential will look like this:

PublicKeyCredential {
    id: 'ABCDESKa23taowh09w0eJG... '.rawId: ArrayBuffer(59),
    response: AuthenticatorAttestationResponse {
        clientDataJSON: ArrayBuffer(121),
        attestationObject: ArrayBuffer(306),},type: 'public-key'
}
Copy the code

Step 4: Send your credentials to your server.

First, you may need to convert the ArrayBuffer to a Base64-encoded string or just a string. You need to decode this in your server.

Follow these specifications to validate credentials in the server. You should then store the credential information and allow the user to log in using this WebAuthn credential.

The login

Step 1: Send a request to the server to log in.

This allows the server to send queries that your front end needs to sign.

Step 2: The server sends the challenge and a list of WebAuthn credentials that the user can log in to.

Specify a PublicKeyCredentialRequestOptions server object, the object contains before signing the gauntlet and user registration certificates of WebAuthn list.

const optionsFromServer = {
    "challenge": "somerandomstring".// Need to convert to ArrayBuffer
    "timeout": 60000."rpId": "mywebsite.com"."allowCredentials": [{"type": "public-key"."id": "AdPc7AjUmsefw37..."   // Need to convert to ArrayBuffer}}]Copy the code

Step 3: Front end sign the challenge.

// make sure you've converted the strings to ArrayBuffer
// as mentioned above
const assertion = await navigator.credentials.get({
    publicKey: optionsFromServer
});
Copy the code

The returned assertion looks like this:

PublicKeyCredential {
    id: 'ABCDESKa23taowh09w0eJG... '.// WebAuthn credential ID
    rawId: ArrayBuffer(59),
    response: AuthenticatorAssertionResponse {
        authenticatorData: ArrayBuffer(191),
        clientDataJSON: ArrayBuffer(118),
        signature: ArrayBuffer(70),     // We need to validate the signature
        userHandle: ArrayBuffer(10),},type: 'public-key'
}
Copy the code

Step 4: Send your assertion to your server and validate.

You may need to convert ArrayBuffers to a string before sending them to the server. Follow the guidelines for verifying assertions.

When an assertion is validated, the user has logged in successfully. Now you can generate your session token or set your cookie and go back to the front end.

A couple of things to consider

If users log in using their laptop’s TouchID, how do you allow them to log in from someone else’s laptop?

If they can only log in from their laptop, they may have a bad user experience. One possible approach is to use WebAuthn as an alternative and always have a back-up login method (for example, using magic links or OTP).

Add multiple WebAuthn credentials to an account.

You may want to have a “Settings” page that allows your users to log in to WebAuthn from other devices, for example, if they want to log in to WebAuthn from their laptop and iPad at the same time. The browser doesn’t know what credentials you have saved for the user on the server, and if your user has registered WebAuthn credentials for their laptop, you need to tell the browser so it doesn’t create a new one. Use the excludeCredentials PublicKeyCredentialCreationOptions.

WebAuthn support

Currently, not all browsers support WebAuthn, but more and more do. Visit the FIDO website for a list of browsers and platforms that support WebAuthn.

The end of the

This should cover the basics of registering and logging in using WebAuthn and help you implement it on the site.

If you want to implement WebAuthn, these documents might help:

  • The React quick start – use WebAuthn login: docs. Cotter. App/quickstart -…
  • WebAuthn SDK Reference: docs. Cotter. app/ sdK-referen…

reference

We used these very useful articles to write this article:

  • WebAuthn Guide: WebAuthn. Guide /
  • WebAuthn Specs from W3C: w3c.github. IO/WebAuthn /

Original text: blog. Zhangbing. Site / 2020/12/28 /…