Prácticas recomendadas para el formulario de OTP de SMS

Es común pedirle a un usuario que proporcione una contraseña de un solo uso (OTP) para confirmar su identidad enviándole un SMS. Estos son algunos casos de uso de las OTP por SMS:

  • Autenticación de dos factores. Además del nombre de usuario y la contraseña, el código OTP por SMS se puede usar como un indicador sólido de que la cuenta pertenece a la persona que recibió el código OTP por SMS.
  • Verificación del número de teléfono. Algunos servicios usan un número de teléfono como identificador principal del usuario. En estos servicios, los usuarios pueden ingresar su número de teléfono y la OTP que reciben por SMS para demostrar su identidad. A veces, se combina con un PIN para constituir una autenticación de dos factores.
  • Recuperación de la cuenta. Cuando un usuario pierde el acceso a su cuenta, debe haber una forma de recuperarla. Enviar un correo electrónico a su dirección de correo electrónico registrada o un OTP por SMS a su número de teléfono son métodos comunes de recuperación de cuentas.
  • Confirmación de pago: En los sistemas de pago, algunos bancos o emisores de tarjetas de crédito solicitan autenticación adicional del pagador por motivos de seguridad. Las OTP por SMS se suelen usar para ese fin.

Sigue leyendo para conocer las prácticas recomendadas para crear formularios de OTP por SMS para estos casos de uso.

Lista de tareas

Para proporcionar la mejor experiencia del usuario con la OTP por SMS, sigue estos pasos:

  • Usa el elemento <input> con lo siguiente:
    • type="text"
    • inputmode="numeric"
    • autocomplete="one-time-code"
  • Usa @BOUND_DOMAIN #OTP_CODE como la última línea del mensaje SMS de OTP.
  • Usa la API de WebOTP.

Usa el elemento <input>

Usar un formulario con un elemento <input> es la práctica recomendada más importante que puedes seguir, ya que funciona en todos los navegadores. Incluso si otras sugerencias de esta publicación no funcionan en algunos navegadores, el usuario podrá ingresar y enviar la OTP de forma manual.

<form action="/verify-otp" method="POST">
  <input type="text"
      inputmode="numeric"
      autocomplete="one-time-code"
      pattern="\d{6}"
      required>
</form>

A continuación, se incluyen algunas ideas para garantizar que un campo de entrada aproveche al máximo la funcionalidad del navegador.

type="text"

Dado que las OTP suelen ser números de cinco o seis dígitos, usar type="number" para un campo de entrada puede parecer intuitivo porque cambia el teclado del dispositivo móvil solo a números. Esto no se recomienda porque el navegador espera que un campo de entrada sea un número contable en lugar de una secuencia de varios números, lo que puede causar un comportamiento inesperado. El uso de type="number" hace que se muestren los botones hacia arriba y hacia abajo junto al campo de entrada. Si se presionan estos botones, se incrementa o disminuye el número y se pueden quitar los ceros iniciales.

Usa type="text" en su lugar. Esto no convertirá el teclado para dispositivos móviles solo en números, pero está bien porque la siguiente sugerencia para usar inputmode="numeric" hace ese trabajo.

inputmode="numeric"

Usa inputmode="numeric" para cambiar el teclado del dispositivo móvil a solo números.

Algunos sitios web usan type="tel" para los campos de entrada de la OTP, ya que también convierte el teclado del dispositivo móvil solo en números (incluidos * y #) cuando está enfocado. Este truco se usaba en el pasado cuando inputmode="numeric" no era ampliamente compatible. Dado que Firefox comenzó a admitir inputmode="numeric", no es necesario usar el hack type="tel" semánticamente incorrecto.

autocomplete="one-time-code"

El atributo autocomplete permite a los desarrolladores especificar qué permiso debe proporcionar el navegador para la asistencia de autocompletado y le informa al navegador sobre el tipo de información que se espera en el campo.

Con autocomplete="one-time-code", cada vez que un usuario recibe un mensaje de SMS mientras hay un formulario abierto, el sistema operativo analizará de forma heurística la OTP en el SMS y el teclado sugerirá la OTP para que el usuario la ingrese. Solo funciona en Safari 12 y versiones posteriores en iOS, iPadOS y macOS, pero te recomendamos que lo uses, ya que es una mejor manera de mejorar la experiencia de OTP por SMS en esas plataformas.

autocomplete="one-time-code" en acción.

autocomplete="one-time-code" mejora la experiencia del usuario, pero puedes hacer más si te aseguras de que el mensaje SMS cumpla con el formato de mensaje vinculado al origen.

Atributos opcionales

Entre los atributos opcionales, se incluyen los siguientes:

Lee nuestras prácticas recomendadas para formularios de acceso y obtén más sugerencias.

Cómo dar formato al texto del SMS

Mejora la experiencia del usuario cuando ingresa un OTP alineándose con la especificación de los códigos únicos vinculados al origen que se entregan por SMS.

Básicamente, la regla de formato es la siguiente: Finaliza el mensaje SMS con el dominio del destinatario precedido por @ y la OTP precedida por #.

Por ejemplo:

Your OTP is 123456

@web-otp.glitch.me #123456

El formato estándar de los mensajes de OTP facilita y hace más confiable la extracción. Asociar códigos OTP con sitios web dificulta que se engañe a los usuarios para que proporcionen un código a sitios maliciosos.

Reglas de formato precisas

Las reglas precisas son las siguientes:

  • El mensaje comienza con texto legible para las personas (opcional) que contiene una cadena alfanumérica de cuatro a diez caracteres con al menos un número, y deja la última línea para la URL y la OTP.
  • La parte del dominio de la URL del sitio web que invocó la API debe estar precedida por @.
  • La URL debe contener un #, seguido del OTP. La cantidad de caracteres debe ser de 140 o menos.

El uso de este formato proporciona varios beneficios:

  • La OTP se vinculará al dominio. Si el usuario se encuentra en dominios distintos del especificado en el mensaje SMS, no aparecerá la sugerencia de OTP. Esto también mitiga el riesgo de ataques de phishing y posibles robos de cuentas.
  • Ahora, el navegador podrá extraer de forma confiable el OTP sin depender de heurísticas misteriosas y poco confiables.

Cuando un sitio web usa autocomplete="one-time-code", Safari con iOS 14 o versiones posteriores sugerirá la OTP según las siguientes reglas.

Este formato de mensaje SMS también beneficia a otros navegadores además de Safari. Chrome, Opera y Vivaldi en Android también admiten la regla de códigos de un solo uso vinculados al origen con la API de WebOTP, aunque no a través de autocomplete="one-time-code".

Usa la API de WebOTP

La API de WebOTP proporciona acceso a la OTP recibida en un mensaje SMS. Cuando se llama a navigator.credentials.get() con el tipo otp (OTPCredential), en el que transport incluye sms, el sitio web esperará a que se entregue un SMS que cumpla con los códigos de un solo uso vinculados al origen y a que el usuario otorgue acceso. Una vez que la OTP se pasa a JavaScript, el sitio web puede usarla en un formulario o enviarla directamente al servidor con POST.

navigator.credentials.get({
  otp: {transport:['sms']}
})
.then(otp => input.value = otp.code);
La API de WebOTP en acción.

Obtén información detallada para usar la API de WebOTP en Cómo verificar números de teléfono en la Web con la API de WebOTP o copia y pega el siguiente fragmento. Asegúrate de establecer un atributo action y method en tu <form>.

// Feature detection
if ('OTPCredential' in window) {
  window.addEventListener('DOMContentLoaded', e => {
    const input = document.querySelector('input[autocomplete="one-time-code"]');
    if (!input) return;
    // Cancel the WebOTP API if the form is submitted manually.
    const ac = new AbortController();
    const form = input.closest('form');
    if (form) {
      form.addEventListener('submit', e => {
        // Cancel the WebOTP API.
        ac.abort();
      });
    }
    // Invoke the WebOTP API
    navigator.credentials.get({
      otp: { transport:['sms'] },
      signal: ac.signal
    }).then(otp => {
      input.value = otp.code;
      // Automatically submit the form when an OTP is obtained.
      if (form) form.submit();
    }).catch(err => {
      console.log(err);
    });
  });
}