Verifica números de teléfono en la Web con la API de WebOTP

Ayuda a los usuarios con las OTP recibidas por SMS

¿Qué es la API de WebOTP?

En la actualidad, la mayoría de las personas del mundo tienen un dispositivo móvil, y los desarrolladores suelen usar números de teléfono como identificador para los usuarios de sus servicios.

Existen varias formas de verificar números de teléfono, pero una contraseña de un solo uso (OTP) generada de forma aleatoria que se envía por SMS es una de las más comunes. El envío de este código al servidor del desarrollador demuestra el control del número de teléfono.

Esta idea ya se implementó en muchos casos para lograr lo siguiente:

  • Número de teléfono como identificador del usuario. Cuando te registras en un servicio nuevo, algunos sitios web solicitan un número de teléfono en lugar de una dirección de correo electrónico y lo usan como identificador de la cuenta.
  • Verificación en dos pasos. Cuando accedes, un sitio web solicita un código de un solo uso que se envía por SMS, además de una contraseña o algún otro factor de conocimiento para mayor seguridad.
  • Confirmación del pago. Cuando un usuario realiza un pago, solicitar un código de un solo uso que se envía por SMS puede ayudar a verificar la intención de la persona.

El proceso actual genera fricciones para los usuarios. Encontrar una OTP dentro de un mensaje SMS y, luego, copiarla y pegarla en el formulario es engorroso, lo que reduce los porcentajes de conversión en los recorridos del usuario críticos. Facilitar este proceso es una solicitud de larga data para la Web de muchos de los desarrolladores globales más grandes. Android tiene una API que hace exactamente esto. Lo mismo sucede con iOS y Safari.

La API de WebOTP permite que tu app reciba mensajes con formato especial vinculados al dominio de tu app. A partir de esto, puedes obtener de forma programática una OTP de un mensaje SMS y verificar un número de teléfono del usuario con mayor facilidad.

Observa cómo funciona

Supongamos que un usuario quiere verificar su número de teléfono con un sitio web. El sitio web envía un mensaje de texto al usuario por SMS, y el usuario ingresa la OTP del mensaje para verificar la propiedad del número de teléfono.

Con la API de WebOTP, estos pasos son tan fáciles como presionar un botón para el usuario, como se muestra en el video. Cuando llega el mensaje de texto, aparece una hoja inferior y se le solicita al usuario que verifique su número de teléfono. Después de hacer clic en el botón Verificar en la hoja inferior, el navegador pega la OTP en el formulario y este se envía sin que el usuario deba presionar Continuar.

Todo el proceso se diagrama en la siguiente imagen.

Diagrama de la API de WebOTP

Prueba la demostración. No te solicita tu número de teléfono ni envía un SMS a tu dispositivo, pero puedes enviar uno desde otro dispositivo si copias el texto que se muestra en la demostración. Esto funciona porque no importa quién sea el remitente cuando se usa la API de WebOTP.

  1. Ve a https://web-otp.glitch.me en Chrome 84 o versiones posteriores en un dispositivo Android.
  2. Envía el siguiente mensaje SMS a tu teléfono desde otro teléfono.
Your OTP is: 123456.

@web-otp.glitch.me #12345

¿Recibiste el SMS y viste el mensaje para ingresar el código en el área de entrada? Así es como funciona la API de WebOTP para los usuarios.

El uso de la API de WebOTP consta de tres partes:

  • Una etiqueta <input> con anotaciones correctas
  • JavaScript en tu app web
  • Texto del mensaje con formato enviado por SMS.

Primero, hablaré de la etiqueta <input>.

Cómo anotar una etiqueta <input>

WebOTP funciona sin ninguna anotación HTML, pero para la compatibilidad con varios navegadores, te recomiendo que agregues autocomplete="one-time-code" a la etiqueta <input> en la que esperas que el usuario ingrese una OTP.

Esto permite que Safari 14 o versiones posteriores sugieran que el usuario autocompleta el campo <input> con una OTP cuando recibe un SMS con el formato que se describe en Formato del mensaje SMS, aunque no admita WebOTP.

HTML

<form>
  <input autocomplete="one-time-code" required/>
  <input type="submit">
</form>

Usa la API de WebOTP

Debido a que WebOTP es simple, solo debes copiar y pegar el siguiente código para que funcione. De cualquier manera, te explicaré lo que sucede.

JavaScript

if ('OTPCredential' in window) {
  window.addEventListener('DOMContentLoaded', e => {
    const input = document.querySelector('input[autocomplete="one-time-code"]');
    if (!input) return;
    const ac = new AbortController();
    const form = input.closest('form');
    if (form) {
      form.addEventListener('submit', e => {
        ac.abort();
      });
    }
    navigator.credentials.get({
      otp: { transport:['sms'] },
      signal: ac.signal
    }).then(otp => {
      input.value = otp.code;
      if (form) form.submit();
    }).catch(err => {
      console.log(err);
    });
  });
}

Detección de atributos

La detección de atributos es la misma que para muchas otras APIs. Si escuchas el evento DOMContentLoaded, se esperará a que el árbol del DOM esté listo para realizar la consulta.

JavaScript

if ('OTPCredential' in window) {
  window.addEventListener('DOMContentLoaded', e => {
    const input = document.querySelector('input[autocomplete="one-time-code"]');
    if (!input) return;
    …
    const form = input.closest('form');
    …
  });
}

Procesa la OTP

La API de WebOTP es bastante simple. Usa navigator.credentials.get() para obtener la OTP. WebOTP agrega una nueva opción otp a ese método. Solo tiene una propiedad: transport, cuyo valor debe ser un array con la cadena 'sms'.

JavaScript

    …
    navigator.credentials.get({
      otp: { transport:['sms'] }
      …
    }).then(otp => {
    …

Esto activa el flujo de permisos del navegador cuando llega un mensaje SMS. Si se otorga el permiso, la promesa que se muestra se resuelve con un objeto OTPCredential.

Contenido del objeto OTPCredential obtenido

{
  code: "123456" // Obtained OTP
  type: "otp"  // `type` is always "otp"
}

A continuación, pasa el valor de la OTP al campo <input>. Si envías el formulario directamente, se eliminará el paso en el que el usuario debe presionar un botón.

JavaScript

    …
    navigator.credentials.get({
      otp: { transport:['sms'] }
      …
    }).then(otp => {
      input.value = otp.code;
      if (form) form.submit();
    }).catch(err => {
      console.error(err);
    });
    …

Cómo abortar el mensaje

En caso de que el usuario ingrese una OTP de forma manual y envíe el formulario, puedes cancelar la llamada a get() con una instancia de AbortController en el objeto options.

JavaScript

    …
    const ac = new AbortController();
    …
    if (form) {
      form.addEventListener('submit', e => {
        ac.abort();
      });
    }
    …
    navigator.credentials.get({
      otp: { transport:['sms'] },
      signal: ac.signal
    }).then(otp => {
    …

Cómo dar formato al mensaje SMS

La API en sí debería ser bastante simple, pero hay algunos aspectos que debes conocer antes de usarla. El mensaje se debe enviar después de llamar a navigator.credentials.get() y se debe recibir en el dispositivo al que se llamó a get(). Por último, el mensaje debe cumplir con el siguiente formato:

  • El mensaje comienza con un texto legible por humanos (opcional) que contiene una cadena alfanumérica de cuatro a diez caracteres con, al menos, un número, dejando la última línea para la URL y la OTP.
  • La parte de dominio de la URL del sitio web que invocó la API debe ir precedida por @.
  • La URL debe contener un signo numeral (#) (“#”) seguido de la OTP.

Por ejemplo:

Your OTP is: 123456.

@www.example.com #123456

Estos son ejemplos de mala calidad:

Ejemplo de texto SMS con el formato incorrecto Por qué esto no funcionará
Here is your code for @example.com #123456 Se espera que @ sea el primer carácter de la última línea.
Your code for @example.com is #123456 Se espera que @ sea el primer carácter de la última línea.
Your verification code is 123456

@example.com\t#123456
Se espera un solo espacio entre @host y #code.
Your verification code is 123456

@example.com  #123456
Se espera un solo espacio entre @host y #code.
Your verification code is 123456

@ftp://example.com #123456
No se puede incluir el esquema de URL.
Your verification code is 123456

@https://example.com #123456
No se puede incluir el esquema de URL.
Your verification code is 123456

@example.com:8080 #123456
No se puede incluir el puerto.
Your verification code is 123456

@example.com/foobar #123456
No se puede incluir la ruta.
Your verification code is 123456

@example .com #123456
No hay espacios en blanco en el dominio.
Your verification code is 123456

@domain-forbiden-chars-#%/:<>?@[] #123456
No hay caracteres prohibidos en el dominio.
@example.com #123456

Mambo Jumbo
Se espera que @host y #code sean la última línea.
@example.com #123456

App hash #oudf08lkjsdf834
Se espera que @host y #code sean la última línea.
Your verification code is 123456

@example.com 123456
Falta #.
Your verification code is 123456

example.com #123456
Falta @.
Hi mom, did you receive my last text Faltan @ y #.

Demostraciones

Prueba varios mensajes con la demostración: https://web-otp.glitch.me

También puedes crear una bifurcación y crear tu versión: https://glitch.com/edit/#!/web-otp.

Usa WebOTP desde un iframe de origen cruzado

Por lo general, se ingresa una OTP por SMS a un iframe de origen cruzado para confirmar el pago, en especial con 3D Secure. Con el formato común para admitir iframes de origen cruzado, la API de WebOTP entrega OTP vinculadas a orígenes anidados. Por ejemplo:

  • Un usuario visita shop.example para comprar un par de zapatos con una tarjeta de crédito.
  • Después de ingresar el número de tarjeta de crédito, el proveedor de pagos integrado muestra un formulario de bank.example dentro de un iframe que le solicita al usuario que verifique su número de teléfono para realizar la confirmación de la compra rápidamente.
  • bank.example envía un SMS que contiene una OTP al usuario para que pueda ingresarla y verificar su identidad.

Para usar la API de WebOTP desde un iframe de origen cruzado, debes hacer dos cosas:

  • Anota el origen del marco superior y el del iframe en el mensaje de texto del SMS.
  • Configura la política de permisos para permitir que el iframe de origen cruzado reciba la OTP directamente del usuario.
La API de WebOTP dentro de un iframe en acción.

Puedes probar la demostración en https://web-otp-iframe-demo.stackblitz.io.

Anota los orígenes vinculados al mensaje de texto SMS

Cuando se llama a la API de WebOTP desde un iframe, el mensaje de texto SMS debe incluir el origen del marco superior precedido por @, seguido de la OTP precedida por # y el origen del iframe precedido por @ en la última línea.

Your verification code is 123456

@shop.example #123456 @bank.exmple

Configura la política de permisos

Para usar WebOTP en un iframe de origen cruzado, el incorporador debe otorgar acceso a esta API a través de la política de permisos de otp-credentials para evitar un comportamiento no deseado. En general, existen dos maneras de lograr este objetivo:

A través del encabezado HTTP:

Permissions-Policy: otp-credentials=(self "https://bank.example")

A través del atributo allow del iframe:

<iframe src="https://bank.example/…" allow="otp-credentials"></iframe>

Consulta más ejemplos para especificar una política de permisos .

Cómo usar WebOTP en una computadora

En Chrome, WebOTP admite la detección de SMS recibidos en otros dispositivos para ayudar a los usuarios a completar la verificación del número de teléfono en computadoras de escritorio.

La API de WebOTP en computadoras de escritorio.

Esta función requiere que el usuario acceda a la misma Cuenta de Google en Chrome para computadoras y Chrome para Android.

Todo lo que los desarrolladores deben hacer es implementar la API de WebOTP en su sitio web para computadoras, de la misma manera que lo hacen en su sitio web para dispositivos móviles, pero no se requieren trucos especiales.

Obtén más detalles en Cómo verificar un número de teléfono en computadoras de escritorio con la API de WebOTP.

Preguntas frecuentes

No aparece el diálogo, aunque envío un mensaje con el formato correcto. ¿Cuál es el problema?

Ten en cuenta las siguientes advertencias cuando pruebes la API:

  • Si el número de teléfono del remitente se incluye en la lista de contactos del destinatario, no se activará esta API debido al diseño de la API de consentimiento del usuario de SMS subyacente.
  • Si usas un perfil de trabajo en tu dispositivo Android y la WebOTP no funciona, intenta instalar y usar Chrome en tu perfil personal (es decir, el mismo perfil en el que recibes mensajes SMS).

Vuelve a consultar el formato para ver si el SMS tiene el formato correcto.

¿Esta API es compatible con diferentes navegadores?

Chromium y WebKit acordaron el formato de mensaje de texto SMS, y Apple anunció la compatibilidad de Safari con él a partir de iOS 14 y macOS Big Sur. Aunque Safari no admite la API de JavaScript de WebOTP, si annotates el elemento input con autocomplete=["one-time-code"], el teclado predeterminado te sugiere automáticamente que ingreses la OTP si el mensaje SMS cumple con el formato.

¿Es seguro usar SMS como forma de autenticación?

Si bien la OTP por SMS es útil para verificar un número de teléfono cuando se proporciona por primera vez, la verificación del número de teléfono por SMS se debe usar con cuidado para la re-autenticación, ya que los operadores pueden apropiarse de los números de teléfono y reciclarlos. WebOTP es un mecanismo conveniente de recuperación y reautorización, pero los servicios deben combinarlo con factores adicionales, como un desafío de conocimiento, o usar la API de Web Authentication para una autenticación sólida.

¿Dónde puedo informar errores en la implementación de Chrome?

¿Encontraste un error en la implementación de Chrome?

  • Informa un error en crbug.com. Incluye tantos detalles como sea posible, instrucciones simples para reproducirlo y establece Componentes en Blink>WebOTP.

¿Cómo puedo ayudar con esta función?

¿Piensas usar la API de WebOTP? Tu apoyo público nos ayuda a priorizar las funciones y les muestra a otros proveedores de navegadores lo importante que es admitirlas. Envía un tuit a @ChromiumDev con el hashtag #WebOTP y cuéntanos dónde y cómo lo usas.

Recursos