Crea una experiencia de acceso que aproveche las llaves de acceso y, al mismo tiempo, se adapte a los usuarios que ya usan contraseñas.
En esta guía, se explica cómo usar el autocompletado de formularios para permitir que los usuarios accedan con llaves de acceso junto con contraseñas. El uso de la función para autocompletar formularios crea una experiencia de acceso unificada, lo que simplifica la transición de las contraseñas al método de autenticación con llaves de acceso, que es más seguro y fácil de usar.
Obtén más información para implementar la IU condicional de WebAuthn y admitir usuarios con llaves de acceso y contraseñas con la menor fricción posible en tus formularios de acceso existentes.
¿Por qué usar el autocompletado de formularios para acceder con una llave de acceso?
Las llaves de acceso permiten que los usuarios accedan a sitios web con su huella dactilar, rostro o PIN del dispositivo.
Si todos los usuarios tuvieran llaves de acceso, el flujo de autenticación podría ser un solo botón de acceso. Si el usuario presiona el botón, podrá verificar directamente la cuenta con el bloqueo de pantalla y acceder.
Sin embargo, la transición de contraseñas a llaves de acceso presenta desafíos. Durante este período, los sitios web deben admitir tanto a los usuarios de contraseñas como a los de llaves de acceso. Esperar que los usuarios recuerden qué sitios usan llaves de acceso y pedirles que elijan un método de acceso por adelantado genera una mala experiencia del usuario.
Además, las llaves de acceso son una tecnología nueva, por lo que explicarlas con claridad puede ser difícil. Usar la interfaz familiar de Autocompletar ayuda a abordar tanto el desafío de la transición como la necesidad de que el usuario se familiarice con ella.
Usa la IU condicional
Para brindar asistencia a los usuarios de contraseñas y llaves de acceso de manera eficaz, incluye llaves de acceso en las sugerencias de autocompletar de tu formulario. Este enfoque utiliza la IU condicional, una función del estándar de WebAuthn.
Cuando el usuario se enfoca en el campo de entrada del nombre de usuario, aparece un diálogo de autocompletado que sugiere las llaves de acceso almacenadas junto con las contraseñas guardadas. El usuario puede seleccionar una llave de acceso o una contraseña y acceder con el bloqueo de pantalla del dispositivo si elige una llave de acceso.
Esto permite que los usuarios accedan a tu sitio web con el formulario de acceso existente, pero con el beneficio de seguridad adicional de las llaves de acceso si tienen una.
Cómo funciona la autenticación con llave de acceso
Para autenticarte con una llave de acceso, debes usar la API de WebAuthn.
Los cuatro componentes de un flujo de autenticación con llave de acceso son los siguientes:
- Backend: Almacena los detalles de la cuenta del usuario, incluida la clave pública.
- Frontend: Se comunica con el navegador y recupera los datos necesarios del backend.
- Navegador: Ejecuta tu código JavaScript y se comunica con la API de WebAuthn.
- Proveedor de llaves de acceso: Crea y almacena la llave de acceso. Por lo general, se trata de un administrador de contraseñas, como el Administrador de contraseñas de Google, o una llave de seguridad.
El proceso de autenticación con llaves de acceso sigue este flujo:
- El usuario visita la página de acceso, y el frontend solicita un desafío de autenticación al backend.
- El backend genera y devuelve un desafío de WebAuthn asociado a la cuenta del usuario.
- El frontend llama a
navigator.credentials.get()con el desafío para iniciar la autenticación con el navegador. - El navegador, que interactúa con el proveedor de llaves de acceso, le solicita al usuario que seleccione una llave de acceso (a menudo, a través de un diálogo de autocompletar que se activa cuando se enfoca el campo de acceso) y que verifique su identidad con el bloqueo de pantalla o los datos biométricos del dispositivo.
- Después de la verificación exitosa del usuario, el proveedor de llaves de acceso firma el desafío, y el navegador devuelve la credencial de clave pública resultante (incluida la firma) al frontend.
- El frontend envía esta credencial al backend.
- El backend verifica la firma de la credencial con la clave pública almacenada del usuario. Si la verificación se realiza correctamente, el backend permite el acceso del usuario.
Cómo autenticarse con una llave de acceso a través del autocompletado de formularios
Para iniciar la autenticación con llave de acceso usando la función de autocompletar formularios, realiza una llamada condicional a WebAuthn get cuando se cargue la página de acceso. Esta llamada a navigator.credentials.get() incluye la opción mediation: 'conditional'.
Una solicitud condicional a la API de WebAuthn
navigator.credentials.get() no muestra la IU de inmediato. En cambio, espera en un estado pendiente hasta que el usuario interactúa con el mensaje de autocompletar del campo de nombre de usuario. Si el usuario selecciona una llave de acceso, el navegador resuelve la promesa pendiente con una credencial para acceder al usuario, lo que omite el envío tradicional del formulario. Si el usuario elige una contraseña, la promesa no se resuelve y continúa el flujo de acceso estándar con contraseña.rm. Luego, es responsabilidad de la página hacer que el usuario acceda.
Anota el campo de entrada del formulario
Para habilitar el autocompletado de llaves de acceso, agrega el atributo autocomplete al campo de nombre de usuario input de tu formulario. Incluye username y webauthn como valores separados por espacios.
<input type="text" name="username" autocomplete="username webauthn" autofocus>
Si agregas autofocus a este campo, se activará automáticamente el mensaje de autocompletar cuando se cargue la página, lo que mostrará de inmediato las contraseñas y llaves de acceso disponibles.
Detección de características
Antes de invocar una llamada condicional a la API de WebAuthn, verifica lo siguiente:
- El navegador admite WebAuthn con
PublicKeyCredential.
- El navegador admite la detección de capacidades con
PublicKeyCredential.getClientCapabilities().
- El navegador admite la IU condicional de WebAuthn con
conditionalGet.
En el siguiente fragmento, se muestra cómo puedes verificar si el navegador admite estas funciones:
if (window.PublicKeyCredential && PublicKeyCredential.getClientCapabilities) {
const capabilities = await PublicKeyCredential.getClientCapabilities();
// Check if conditional mediation is available.
if (capabilities.conditionalGet === true) {
// The browser supports conditional mediation.
}
}
Recupera información del backend
Tu backend debe proporcionar varias opciones al frontend para iniciar la llamada navigator.credentials.get(). Por lo general, estas opciones se recuperan como un objeto JSON de un extremo en tu servidor.
Las propiedades clave del objeto de opciones incluyen las siguientes:
challenge: Es un desafío generado por el servidor en un ArrayBuffer (por lo general, codificado en Base64URL para el transporte de JSON). Esto es fundamental para evitar ataques de repetición. Tu servidor debe generar un desafío nuevo para cada intento de acceso y debe invalidarlo después de un breve período o si falla un intento.allowCredentials: Es un array de descriptores de credenciales. Pasa un array vacío. Esto le indica al navegador que enumere todas las credenciales para elrpIdespecificado.userVerification: Especifica tu preferencia para la verificación del usuario, como requerir un bloqueo de pantalla del dispositivo. El valor predeterminado y recomendado es"preferred". Los valores posibles son los siguientes:"required": El autenticador debe realizar la verificación del usuario (por ejemplo, con un PIN o datos biométricos). La operación falla si no se puede realizar la verificación."preferred": El autenticador intenta verificar al usuario, pero la operación puede completarse sin hacerlo."discouraged": Si es posible, el autenticador debe evitar la verificación del usuario.
rpId: Es el ID de tu entidad de confianza, que suele ser el dominio de tu sitio web (comoexample.com). Este valor debe coincidir exactamente con elrp.idque se usó cuando se creó la credencial de llave de acceso.
Tu servidor debe construir este objeto de opciones. Los valores de ArrayBuffer (como challenge) deben codificarse en Base64URL para el transporte de JSON. En el frontend, después de analizar el JSON, usa PublicKeyCredential.parseRequestOptionsFromJSON() para convertir el objeto (incluida la decodificación de cadenas Base64URL) en el formato que espera navigator.credentials.get().
En el siguiente fragmento de código, se muestra cómo puedes recuperar y decodificar la información necesaria para autenticarte con una llave de acceso.
// Fetch an encoded PubicKeyCredentialRequestOptions from the server.
const _options = await fetch('/webauthn/signinRequest');
// Deserialize and decode the PublicKeyCredentialRequestOptions.
const decoded_options = JSON.parse(_options);
const options = PublicKeyCredential.parseRequestOptionsFromJSON(decoded_options);
...
Llama a la API de WebAuthn con la marca conditional para autenticar al usuario.
Una vez que tengas preparado el objeto publicKeyCredentialRequestOptions (al que se hace referencia como options en el siguiente código de ejemplo), llama a navigator.credentials.get() para iniciar la autenticación condicional con llave de acceso.
// To abort a WebAuthn call, instantiate an AbortController.
const abortController = new AbortController();
// Invoke WebAuthn to authenticate with a passkey.
const credential = await navigator.credentials.get({
publicKey: options,
signal: abortController.signal,
// Specify 'conditional' to activate conditional UI
mediation: 'conditional'
});
Parámetros clave para esta llamada:
publicKey: Debe ser el objetopublicKeyCredentialRequestOptions(llamadooptionsen el ejemplo) que recuperaste de tu servidor y procesaste en el paso anterior.signal: Pasar un objetoAbortController(comoabortController.signal) te permite cancelar de forma programática la solicitud deget(). Esto es útil cuando deseas invocar otra llamada de WebAuthn.mediation: 'conditional': Esta es la marca crucial que hace que la llamada a WebAuthn sea condicional. Indica al navegador que espere la interacción del usuario con un mensaje de autocompletado en lugar de mostrar inmediatamente un diálogo modal.
Envía la credencial de clave pública que se devolvió al servidor de RP
Si el usuario selecciona una llave de acceso y verifica su identidad correctamente (por ejemplo, con el bloqueo de pantalla del dispositivo), se resuelve la promesa de navigator.credentials.get(). Esto devuelve un objeto PublicKeyCredential a tu frontend.
La promesa se puede rechazar por varios motivos. Debes controlar estos errores en tu código verificando la propiedad name del objeto Error:
NotAllowedError: El usuario canceló la operación o no se seleccionó ninguna llave de acceso.AbortError: Se anuló la operación, posiblemente por tu código con unAbortController.- Otras excepciones: Se produjo un error inesperado. Por lo general, el navegador muestra un diálogo de error al usuario.
El objeto PublicKeyCredential contiene varias propiedades. Las propiedades clave relevantes para la autenticación incluyen las siguientes:
id: Es el ID codificado en Base64URL de la credencial de llave de acceso autenticada.rawId: Es una versión de ArrayBuffer del ID de credencial.response.clientDataJSON: Un ArrayBuffer de datos del cliente. Este campo contiene información, como el desafío y el origen que tu servidor debe verificar.response.authenticatorData: Un ArrayBuffer de datos del autenticador. Este campo incluye información como el ID del RP.response.signature: Un ArrayBuffer que contiene la firma. Este valor es el núcleo de la credencial, y tu servidor debe verificar esta firma con la clave pública almacenada para la credencial .response.userHandle: Un ArrayBuffer que contiene el ID de usuario proporcionado durante el registro de la llave de acceso.authenticatorAttachment: Indica si el autenticador forma parte del dispositivo cliente (platform) o es externo (cross-platform). Se puede producir una vinculacióncross-platformsi el usuario accedió con un teléfono. En esos casos, considera pedirles que crean una llave de acceso en el dispositivo actual para mayor comodidad en el futuro.type: Este campo siempre se establece en"public-key".
Para enviar este objeto PublicKeyCredential a tu backend, primero llama al método .toJSON(). Este método crea una versión serializable en JSON de la credencial, que controla correctamente la conversión de las propiedades ArrayBuffer (como rawId, clientDataJSON, authenticatorData, signature y userHandle) en cadenas codificadas en Base64URL. Luego, usa JSON.stringify() para convertir este objeto en una cadena y enviarlo en el cuerpo de la solicitud al servidor.
...
// Encode and serialize the PublicKeyCredential.
const _result = credential.toJSON();
const result = JSON.stringify(_result);
// Encode and send the credential to the server for verification.
const response = await fetch('/webauthn/signinResponse', {
method: 'post',
credentials: 'same-origin',
body: result
});
Verifica la firma
Cuando tu servidor de backend recibe la credencial de clave pública, debe verificar su autenticidad. Esto incluye lo siguiente:
- Analiza los datos de las credenciales.
- Se busca la clave pública almacenada asociada con el
idde la credencial. - Verificar el
signaturerecibido con la clave pública almacenada - Validar otros datos, como el desafío y el origen
Recomendamos usar una biblioteca FIDO/WebAuthn del servidor para controlar estas operaciones criptográficas de forma segura. Puedes encontrar bibliotecas de código abierto en el repositorio de GitHub awesome-webauthn.
Si la firma y todas las demás aserciones son válidas, el servidor puede permitir el acceso del usuario. Para conocer los pasos detallados de la validación del servidor, consulta Autenticación con llave de acceso del servidor.
Indica si no se encontraron las credenciales coincidentes en el backend.
Si tu servidor de backend no puede encontrar una credencial con un ID coincidente durante el acceso, es posible que el usuario haya borrado previamente esta llave de acceso de tu servidor, pero no de su proveedor de llaves de acceso. Esta falta de coincidencia puede generar una experiencia del usuario confusa si el proveedor de llaves de acceso sigue sugiriendo una llave de acceso que ya no funciona con tu sitio. Para mejorar esto, debes indicarle al proveedor de llaves de acceso que quite la llave de acceso huérfana.
Puedes usar el método PublicKeyCredential.signalUnknownCredential(), que forma parte de la API de WebAuthn Signal, para informar al proveedor de llaves de acceso que se quitó la credencial especificada o que no existe. Llama a este método estático del lado del cliente si tu servidor indica (por ejemplo, con un código de estado HTTP específico, como 404) que no se conoce un ID de credencial presentado. Proporciona el ID de RP y el ID de credencial desconocido a este método. El proveedor de llaves de acceso, si admite el indicador, debe quitar la llave de acceso.
// Detect authentication failure due to lack of the credential
if (response.status === 404) {
// Feature detection
if (PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId: "example.com",
credentialId: "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA" // base64url encoded credential ID
});
} else {
// Encourage the user to delete the passkey from the password manager nevertheless.
...
}
}
Después de la autenticación
Según cómo accedió el usuario, sugerimos diferentes flujos a seguir.
Si el usuario accedió sin una llave de acceso
Si el usuario accedió a tu sitio web sin una llave de acceso, es posible que no tenga una registrada para esa cuenta o en su dispositivo actual. Este es un momento oportuno para fomentar la creación de llaves de acceso. Considera los siguientes enfoques:
- Actualiza las contraseñas a llaves de acceso: Usa conditional create, una función de WebAuthn que permite que el navegador cree automáticamente una llave de acceso para el usuario después de que este accede correctamente con una contraseña. Esto puede mejorar significativamente la adopción de llaves de acceso, ya que simplifica el proceso de creación. Obtén más información sobre cómo funciona y cómo implementarlo en Ayuda a los usuarios a adoptar las llaves de acceso de forma más fluida
- Solicitar manualmente la creación de una llave de acceso: Alienta a los usuarios a crear una llave de acceso. Esto puede ser eficaz después de que un usuario completa un proceso de acceso más complejo, como la autenticación de varios factores (MFA). Sin embargo, evita el uso excesivo de mensajes, ya que pueden ser intrusivos para la experiencia del usuario".
Para ver cómo puedes alentar a los usuarios a crear una llave de acceso y conocer otras prácticas recomendadas, consulta los ejemplos en Cómo comunicar las llaves de acceso a los usuarios.
Si el usuario accedió con una llave de acceso
Después de que un usuario accede correctamente con una llave de acceso, tienes varias oportunidades para mejorar aún más su experiencia y mantener la coherencia de la cuenta.
Fomentar la creación de una nueva llave de acceso después de una autenticación multidispositivo
Si un usuario accede con una llave de acceso a través de un mecanismo multidispositivo (por ejemplo, escanear un código QR con su teléfono), es posible que la llave de acceso que usó no se almacene de forma local en el dispositivo en el que está accediendo. Esto puede suceder en los siguientes casos:
- Tienen una llave de acceso, pero en un proveedor que no admite el sistema operativo ni el navegador de acceso.
- Perdió el acceso al proveedor de llaves de acceso en el dispositivo en el que intenta acceder, pero aún hay una llave de acceso disponible en otro dispositivo.
En esta situación, considera pedirle al usuario que cree una nueva llave de acceso en el dispositivo actual. Esto puede evitar que repitan el proceso de acceso en varios dispositivos en el futuro. Para determinar si el usuario accedió con una llave de acceso multidispositivo, verifica la propiedad authenticatorAttachment de la credencial. Si su valor es "cross-platform", indica una autenticación en varios dispositivos. Si es así, explícale la comodidad de crear una llave de acceso nueva y guíalo durante el proceso de creación.
Sincroniza los detalles de la llave de acceso con el proveedor a través de indicadores
Para garantizar la coherencia y una mejor experiencia del usuario, tu parte de confianza (RP) puede usar la API de WebAuthn Signals para comunicar actualizaciones sobre las credenciales y la información del usuario al proveedor de claves de acceso.
Por ejemplo, para mantener precisa la lista de llaves de acceso de un usuario del proveedor de llaves de acceso, mantén sincronizadas las credenciales en el backend. Puedes indicar que ya no existe una llave de acceso para que los proveedores de llaves de acceso puedan quitar las llaves de acceso innecesarias.
Del mismo modo, puedes indicar si un usuario actualiza su nombre de usuario o nombre visible en tu servicio para mantener actualizada la información del usuario que muestra el proveedor de claves de acceso (por ejemplo, en los diálogos de selección de cuentas).
Para obtener más información sobre las prácticas recomendadas para mantener la coherencia de las llaves de acceso, consulta Cómo mantener la coherencia entre las llaves de acceso y las credenciales de tu servidor con la API de Signal.
No solicitar un segundo factor
Las llaves de acceso ofrecen protección integrada y sólida contra amenazas comunes, como el phishing. Por lo tanto, un segundo factor de autenticación no agrega un valor de seguridad significativo. En cambio, crea un paso innecesario para los usuarios durante el acceso.
Lista de tareas
- Permitir que los usuarios accedan con una llave de acceso a través del autocompletado de formularios
- Indica cuando no se encuentra la credencial coincidente de una llave de acceso en el backend.
- Solicitar a los usuarios que creen una llave de acceso de forma manual si aún no lo hicieron después de acceder
- Crear automáticamente una llave de acceso (creación condicional) después de que el usuario acceda con una contraseña (y un segundo factor)
- Solicita la creación de una llave de acceso local si el usuario accedió con una llave de acceso multidispositivo.
- Indicar al proveedor la lista de llaves de acceso disponibles y los detalles del usuario actualizados (nombre de usuario, nombre visible) después del acceso o cuando se produzcan cambios
Recursos
- Autenticación con llave de acceso del servidor
- Crea una llave de acceso para los accesos sin contraseña
- Ayuda a los usuarios a administrar las llaves de acceso de manera eficaz
- Llaves de acceso
- Documento de Apple: Authenticating a User Through a Web Service (Cómo autenticar a un usuario a través de un servicio web)
- Documento de Google: Accede sin contraseñas con llaves de acceso