Webauthn
Published: 2022-12-10 16:04:16

⚠️ **Important note:** All the text of this post (excluding this note) is genarated using openGPT. I am only testing it's abilities to write something detailed.
***

WebAuthn is a web-based authentication standard that allows users to securely log in to websites and applications using biometric information, such as fingerprints or facial recognition data, or a hardware security key, such as a USB key. The goal of WebAuthn is to provide a more secure and user-friendly alternative to traditional username and password-based authentication methods.

WebAuthn is supported by most modern web browsers and is considered to be one of the most secure authentication methods currently available. It uses public key cryptography to securely authenticate users and prevent fraud or unauthorized access to accounts.

To use WebAuthn, a user must first register with a website or application by creating a new public key. This public key is then stored on the website's servers, and is used to verify the user's identity whenever they log in. When a user attempts to log in, the website or application will challenge the user to prove their identity by providing the corresponding private key. This can be done using biometric information, or by inserting a hardware security key into a USB port.

If the private key is successfully provided and verified, the user is authenticated and allowed access to their account. WebAuthn also supports additional security measures, such as requiring multiple forms of authentication or imposing time-based constraints on authentication attempts.

Overall, WebAuthn provides a more secure and convenient way for users to log in to websites and applications, and helps protect against common threats such as phishing attacks and password reuse.

Let's see a code sample.

```javascript
// Register a new user
async function register() {
  // Collect user credentials
  const credentials = {
    id: 'user-id-123',
    name: 'John Doe',
    displayName: 'JohnDoe',
    icon: 'https://example.com/john-doe-avatar.png'
  };

  // Generate a new public key for the user
  const publicKey = await window.crypto.subtle.generateKey(
    {
      name: 'RSASSA-PKCS1-v1_5',
      hash: 'SHA-256',
      modulusLength: 2048,
      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
    },
    true,
    ['sign', 'verify']
  );

  // Store the public key in the database
  const storedPublicKey = await storePublicKey(credentials.id, publicKey);

  // Register the user with the WebAuthn API
  await navigator.credentials.create({
    publicKey: {
      rp: {
        id: 'example.com',
        name: 'Example Website',
      },
      user: {
        id: credentials.id,
        name: credentials.name,
        displayName: credentials.displayName,
        icon: credentials.icon,
      },
      pubKeyCredParams: [
        {
          type: 'public-key',
          alg: -7,
        },
      ],
      timeout: 60000,
      challenge: generateChallenge(),
      attestation: 'direct',
      authenticatorSelection: {
        requireResidentKey: true,
        userVerification: 'preferred',
      },
    },
  });
}

// Authenticate a user
async function login() {
  // Collect user credentials
  const credentials = {
    id: 'user-id-123',
    name: 'John Doe',
    displayName: 'JohnDoe',
    icon: 'https://example.com/john-doe-avatar.png'
  };

  // Fetch the user's public key from the database
  const publicKey = await fetchPublicKey(credentials.id);

  // Authenticate the user with the WebAuthn API
  const credential = await navigator.credentials.get({
    publicKey: {
      rpId: 'example.com',
      challenge: generateChallenge(),
      allowCredentials: [
        {
          id: credentials.id,
          type: 'public-key',
          transports: ['usb', 'nfc', 'ble'],
        },
      ],
      timeout: 60000,
      userVerification: 'preferred',
    },
  });

  // Verify the authentication signature
  const isValid = await window.crypto.subtle.verify(
    {
      name: 'RSASSA-PKCS1-v1_5',
    },
    publicKey,
    credential.response.signature,
    credential.response.clientDataJSON
  );

  if (isValid) {
    // The authentication was successful
  } else {
    // The authentication was unsuccessful
  }
}
```