Presentamos sugerencias, solicitudes de origen relacionadas y serialización JSON para WebAuthn en Chrome

Chrome 128 y 129 presentan funciones nuevas y emocionantes para WebAuthn, la API subyacente para compilar sistemas de autenticación basados en llaves de acceso.

  • Pistas: Las sugerencias les brindan a los usuarios de confianza (RP) un mejor control sobre la IU de WebAuthn en el navegador. Son especialmente útiles para los usuarios empresariales que desean usar llaves de seguridad.
  • Solicitudes de origen relacionadas: Con las solicitudes de origen relacionadas, los RP pueden hacer que las llaves de acceso sean válidas en varios dominios. Si tienes varios sitios, ahora puedes permitir que los usuarios reutilicen su llave de acceso en todos ellos, lo que elimina los problemas de acceso.
  • Serialización de JSON: Las APIs de serialización de JSON te permiten simplificar el código del frontend de un RP mediante la codificación y decodificación de opciones y credenciales que se pasan a la API de WebAuthn y desde ella.

Sugerencias

Con hints, las partes de confianza (RP) ahora pueden especificar preferencias de la IU para crear una llave de acceso o autenticarse con una.

Anteriormente, cuando un RP quería restringir el autenticador con el que el usuario podía crear una llave de acceso o autenticarse, podía usar authenticatorSelection.authenticatorAttachment para especificar "platform" o "cross-platform". Limitan, respectivamente, el autenticador a un autenticador de plataforma o a un autenticador de roaming. Con hints, esta especificación puede ser más flexible.

El RP puede usar hints opcional en PublicKeyCredentialCreationOptions o PublicKeyCredentialRequestOptions para especificar "security-key", "client-device" y "hybrid" en un orden de preferencia en un array.

El siguiente es un ejemplo de solicitud de creación de credenciales que prefiere autenticadores "cross-platform" con "security-key" como sugerencia. Esto le indica a Chrome que muestre una IU enfocada en la clave de seguridad para los usuarios empresariales.

const credential = await navigator.credentials.create({
  publicKey: {
    challenge: *****,
    hints: ['security-key'],
    authenticatorSelection: {
      authenticatorAttachment: 'cross-platform'
    }
  }
});
Cuando especificas "security-key" como una sugerencia, el navegador muestra un diálogo enfocado en la llave de seguridad.
Cuando especificas "security-key" como una sugerencia, el navegador muestra un diálogo enfocado en la llave de seguridad.

Cuando un RP quiere priorizar una situación de verificación multidispositivo, puede enviar una solicitud de autenticación que prefiera autenticadores "cross-platform" con "hybrid" como sugerencia.

const credential = await navigator.credentials.create({
  publicKey: {
    challenge: *****,
    residentKey: true,
    hints: ['hybrid']
    authenticatorSelection: {
      authenticatorAttachment: 'cross-platform'
    }
  }
});
Si especificas "hybrid" como sugerencia, el navegador muestra un diálogo enfocado en el acceso en varios dispositivos.
Cuando especificas "hybrid" como una sugerencia, el navegador muestra un diálogo enfocado en el acceso en varios dispositivos.

Con las solicitudes de origen relacionadas, las RP pueden hacer que las llaves de acceso se puedan usar desde varios dominios. Crear una experiencia de acceso centralizada y usar protocolos de integración sigue siendo la solución recomendada para la mayoría de los sitios. Sin embargo, si tienes varios dominios y no es posible la integración, los orígenes relacionados pueden ser una solución.

Todas las solicitudes de WebAuthn deben especificar un ID de la parte de confianza (ID de RP), y todas las llaves de acceso están asociadas con un solo ID de RP. Tradicionalmente, un origen solo podía especificar un ID de RP según su dominio, por lo que, en ese caso, www.example.co.uk podía especificar un ID de RP de example.co.uk, pero no de example.com. Con las solicitudes de origen relacionadas, se puede validar un ID de RP reclamado recuperando un archivo JSON conocido ubicado en /.well-known/webauthn desde el dominio de destino. Por lo tanto, example.co.uk (y example.in, example.de, etc.) podrían usar un ID de RP de example.com si example.com los especifica en el siguiente formato:

URL: https://example.com/.well-known/webauthn

{
  "origins": [
    "https://example.co.uk",
    "https://example.de",
    "https://example.sg",
    "https://example.net",
    "https://exampledelivery.com",
    "https://exampledelivery.co.uk",
    "https://exampledelivery.de",
    "https://exampledelivery.sg",
    "https://myexamplerewards.com",
    "https://examplecars.com"
  ]
}

Obtén más información para configurar solicitudes de origen relacionadas en Cómo permitir la reutilización de llaves de acceso en tus sitios con solicitudes de origen relacionadas.

Serialización de JSON

Los objetos de solicitud y respuesta de WebAuthn tienen varios campos que contienen datos binarios sin procesar en un ArrayBuffer, como el ID de la credencial, el ID de usuario o el desafío. Si un sitio web quiere usar JSON para intercambiar estos datos con su servidor, primero se deben codificar los datos binarios, por ejemplo, con Base64URL. Esto agrega complejidad innecesaria para los desarrolladores que desean comenzar a usar llaves de acceso en sus sitios web.

WebAuthn ahora ofrece APIs para analizar los objetos de solicitud de WebAuthn PublicKeyCredentialCreationOptions y PublicKeyCredentialRequestOptions directamente desde JSON y serializar la respuesta de PublicKeyCredential directamente en JSON. Todos los campos con valores de ArrayBuffer que contienen datos binarios sin procesar se convierten automáticamente a sus valores codificados en Base64URL o desde ellos. Estas APIs están disponibles a partir de Chrome 129.

Antes de crear una llave de acceso, recupera un objeto PublicKeyCredentialCreationOptions codificado en JSON del servidor y decodifica con PublicKeyCredential.parseCreationOptionsFromJSON().

Navegadores compatibles

  • Chrome: 129.
  • Edge: 129.
  • Firefox: 119.
  • Safari: No se admite.

Origen

export async function registerCredential() {

  // Fetch encoded `PublicKeyCredentialCreationOptions`
  // and JSON decode it.
  const options = await fetch('/auth/registerRequest').json();

  // Decode `PublicKeyCredentialCreationOptions` JSON object
  const decodedOptions = PublicKeyCredential.parseCreationOptionsFromJSON(options);  

  // Invoke the WebAuthn create() function.
  const cred = await navigator.credentials.create({
    publicKey: decodedOptions,
  });
  ...

Después de crear una llave de acceso, codifica la credencial resultante con toJSON() para que se pueda enviar al servidor.

Navegadores compatibles

  • Chrome: 129
  • Edge: 129.
  • Firefox: 119.
  • Safari: No se admite.

Origen

  ...
  const cred = await navigator.credentials.create({
    publicKey: options,
  });

  // Encode the credential to JSON and stringify
  const credential = JSON.stringify(cred.toJSON());

  // Send the encoded credential to the server
  await fetch('/auth/registerResponse', credential);
  ...

Antes de autenticar con una llave de acceso, recupera un PublicKeyRequestCreationOptions codificado en JSON del servidor y decódalo con PublicKeyCredential.parseRequestOptionsFromJSON().

Navegadores compatibles

  • Chrome: 129.
  • Edge: 129.
  • Firefox: 119.
  • Safari: No se admite.

Origen

export async function authenticate() {

  // Fetch encoded `PublicKeyCredentialRequestOptions`
  // and JSON decode it.
  const options = await fetch('/auth/signinRequest').json();

  // Decode `PublicKeyCredentialRequestOptions` JSON object
  const decodedOptions = PublicKeyCredential.parseRequestOptionsFromJSON(options);

  // Invoke the WebAuthn get() function.
  const cred = await navigator.credentials.get({
    publicKey: options
  });
  ...

Después de autenticarte con una llave de acceso, codifica la credencial resultante con el método toJSON() para que se pueda enviar al servidor.

Navegadores compatibles

  • Chrome: 129.
  • Edge: 129.
  • Firefox: 119.
  • Safari: No se admite.

Origen

  ...
  const cred = await navigator.credentials.get({
    publicKey: options
  });

  // Encode the credential to JSON and stringify
  const credential = JSON.stringify(cred.toJSON());

  // Send the encoded credential to the server
  await fetch(`/auth/signinResponse`, credential);
  ...

Más información

Para obtener más información sobre WebAuthn y las llaves de acceso, consulta los siguientes recursos: