Webauthn | Javascript Client

WebAuthn (Web Authentication API) es un estándar W3C que permite la autenticación segura sin contraseña mediante criptografía de clave pública. En lugar de contraseñas, los usuarios se registran y autentican usando autenticadores basados en hardware (como lectores de huellas dactilares, Face ID, YubiKeys, etc.) o autenticadores de plataforma (integrados, como Touch ID).

 

A continuación se explica cómo manejar el Registro y la Autenticación usando un cliente Javascript.

Registro WebAuthn

Cómo funciona el registro de WebAuthn

 

 

 

El componente TsgcWSAPIServer_WebAuthn incluye un archivo HTML para probar el protocolo WebAuthn. Este archivo HTML contiene una interfaz mínima y código JavaScript para interactuar con WebAuthn.

 

Descripción detallada de sgcWebAuthn.html

 

Descripción general de la estructura:

 

 

 

1. Interfaz HTML para entrada de datos

 

<input type="text" id="username" name="username" autocomplete="username webauthn" />
<button id="btnRegBegin"><strong>Register</strong></button>

 

2. JavaScript: Controlador de clic en botón

 

document.querySelector('#btnRegBegin').addEventListener('click', async () => {
  const username = document.getElementById("username").value;
  if (username == "") {
    document.getElementById('Error').innerText = 'Please enter a username to register';
    return;
}

  const resp = await fetch('<#webauthn_registration_options>', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username, algorithms: [] })
});

  const options = await resp.json();
const attResp = await startRegistration(options);  // WebAuthn API

 

3. Respuesta del servidor (endpoint ficticio en HTML)

 

fetch('/sgcWebAuthn/Registration/Options', ...)

fetch('/sgcWebAuthn/Registration/Verify', ...)

 

4. Finalización del registro

 

const verificationResp = await fetch('/webauthn/register/verify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(attResp)
});

const verificationJSON = await verificationResp.json();
if (verificationJSON && verificationJSON.verified) {
  document.getElementById('Success').innerHTML = `Authenticator registered!`;
}

 

 

 

Autenticación WebAuthn

Cómo funciona la autenticación WebAuthn

 

 

1. Configuración de la interfaz HTML

 

<div class="container">
<h1>WebAuthn Authentication Sample</h1>

  <section id="userdata">
    <label for="username">Username:</label>
    <input type="text" id="username" name="username" autocomplete="username webauthn" autofocus />
</section>

  <button id="btnAuthBegin"><strong>Authenticate</strong></button>

  <p id="Success" class="success"></p>
<p id="Error" class="error"></p>

  <details open>
    <summary>Console</summary>
    <textarea id="Debug"></textarea>
  </details>
</div>

 

2. Obtener opciones de autenticación

 

Antes de llamar a startAuthentication, envíe el nombre de usuario al servidor

 

const resp = await fetch('<#webauthn_authentication_options>', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: document.getElementById("username").value,
    user_verification: 'preferred'
  }),
});

 

El servidor responde con un objeto JSON que incluye:

 

{
  "challenge": "base64url-encoded-random-string",
  "allowCredentials": [
    {
      "id": "base64url-credential-id",
      "type": "public-key"
    }
  ],
  "userVerification": "preferred",
  "rpId": "yourdomain.com"
}

 

Esto se denomina PublicKeyCredentialRequestOptions.

 

 

3. Recibir la respuesta del autenticador

 

La respuesta asseResp tiene el siguiente aspecto (simplificada):

 

{
  "id": "credentialId",
  "rawId": "base64url-encoded-id",
  "response": {
    "authenticatorData": "...",
    "clientDataJSON": "...",
    "signature": "...",
    "userHandle": "..."
  },
  "type": "public-key",
  "clientExtensionResults": {}
}

 

Esta respuesta demuestra que el usuario:

 

 

 

4. Enviar la Respuesta de Autenticación Firmada al Servidor

 

Después de que el usuario interactúa con su autenticador (a través de startAuthentication()), se obtiene un objeto de respuesta en JavaScript.

 

const verificationResp = await fetch('/webauthn/authenticate/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(asseResp), // this is the signed response
});

 

 

5. Obtener la respuesta del servidor

 

El servidor responderá con un resultado como este:

 

{ "verified": true }

 

O si algo salió mal:

 

{ "verified": false, "error": "Invalid signature" }

 

Y lo gestiona en su código de frontend:

 

const result = await verificationResp.json();

if (result.verified) {
  document.getElementById('Success').textContent = 'User authenticated!';
} else {
  document.getElementById('Error').textContent = 'Authentication failed!';
}