Blog
Feature
6 de febrero de 20269 min

Autenticación con código QR: el patrón de WhatsApp Web con Supabase

Para conectar el sitio web a la aplicación móvil, quería algo instantáneo. Sin formularios, sin contraseñas que volver a escribir. El patrón de WhatsApp Web: escanear un código QR y, ¡boom!, conectado. Así es como implementé este sistema en TAMSIV con Supabase Realtime, un fallback de polling y una UX que impresiona.

Puntos clave a recordar:
- El código QR codifica un UUID de sesión único; el sitio se suscribe en tiempo real a través de Supabase Realtime.
- Un fallback de polling HTTP (cada 2 segundos) toma el relevo si Realtime falla después de 3 segundos.
- El código QR expira después de 5 minutos y se regenera automáticamente a los 4 minutos y 30 segundos con una cuenta regresiva visual.
- Todo el sistema ocupa 300 líneas en el lado web y 150 en el lado móvil.

¿Por qué elegir la autenticación por código QR en lugar de un formulario clásico?

La autenticación clásica (correo electrónico + contraseña) funciona. Pero crea fricción. El usuario ya tiene una cuenta en la aplicación móvil. Pedirle que vuelva a escribir sus credenciales en la web es obligarle a recordar una contraseña, posiblemente buscarla en su gestor y arriesgarse a un fallo.

El código QR elimina esta fricción. El usuario ya está autenticado en su teléfono. Escanear un código lleva 2 segundos. Es el patrón popularizado por WhatsApp Web, Telegram y Discord. Los usuarios lo conocen y lo esperan.

Para TAMSIV, esto es aún más relevante ya que el sitio web sirve como complemento de la aplicación móvil, no como reemplazo. El código QR materializa este vínculo entre las dos plataformas.

Persona escaneando un código QR mostrado en la pantalla de un portátil con su smartphone para iniciar sesión
Escanear un código QR lleva 2 segundos, frente a los 30 segundos de un formulario de correo electrónico/contraseña.

¿Cómo funciona el flujo de autenticación por código QR?

Desde el punto de vista del usuario, es mágico: escaneo, estoy conectado. Desde el punto de vista técnico, es un ballet preciso de tokens y canales en tiempo real. Aquí están los pasos:

  1. Generación: el usuario abre tamsiv.com. El sitio genera un UUID de sesión único y crea una entrada en Supabase con el estado "pending".
  2. Visualización: el código QR codifica este UUID. El sitio se suscribe al canal Supabase Realtime para esta sesión.
  3. Escaneo: el usuario escanea el código QR con la aplicación móvil TAMSIV. La aplicación decodifica el UUID.
  4. Confirmación: la aplicación envía su JWT existente + el UUID al backend. El backend verifica el JWT, genera un token de autenticación web y actualiza la sesión a "confirmed".
  5. Conexión: el sitio recibe la actualización a través de Realtime, recupera el token y el usuario está conectado.

Este flujo garantiza que solo un usuario ya autenticado en la aplicación móvil pueda confirmar la sesión. El token generado para la web tiene una vida útil limitada y es independiente del token móvil; ambas sesiones están separadas.

¿Cómo permite Supabase Realtime la conexión instantánea?

Supabase Realtime es el componente que hace que la experiencia sea instantánea. Cuando la aplicación móvil confirma la sesión, el cambio en la base de datos es detectado por el canal Realtime y enviado al navegador, en cuestión de milisegundos.

Técnicamente, el sitio se suscribe a un canal específico que filtra por el UUID de la sesión:

supabase.channel('qr-auth-SESSION_UUID')
  .on('postgres_changes', { event: 'UPDATE', filter: `id=eq.SESSION_UUID` }, callback)
  .subscribe()

El callback se activa tan pronto como el estado cambia de "pending" a "confirmed". El token de autenticación se incluye en la actualización. El usuario ve cómo la página de inicio de sesión se transforma en el panel de control, sin ninguna acción adicional.

Es el mismo mecanismo Realtime que utilizo para el caché de contenido y las actualizaciones en vivo en los grupos colaborativos.

Diagrama arquitectónico que muestra el flujo de autenticación en tiempo real entre una aplicación móvil y un navegador web
El flujo completo: generación del QR, escaneo móvil, confirmación vía JWT, conexión web vía Realtime.

¿Por qué es indispensable un fallback de polling?

Supabase Realtime funciona muy bien en la mayoría de los casos. Pero "la mayoría" no es suficiente para una función de autenticación. Algunas redes corporativas bloquean los WebSockets. Algunos proxies los interrumpen. Algunos navegadores tienen errores específicos.

Implementé un fallback de polling HTTP que toma el relevo automáticamente:

  • El sitio intenta la conexión Realtime durante 3 segundos
  • Si la conexión falla, cambia silenciosamente a un polling HTTP cada 2 segundos
  • El polling consulta directamente la base de datos: "¿está confirmada la sesión UUID?"
  • El usuario nunca sabe qué mecanismo se utiliza; la experiencia es idéntica

El retraso de 3 segundos es un compromiso entre reactividad y fiabilidad. Más corto, pasaríamos demasiado rápido al polling (menos eficiente). Más largo, el usuario esperaría sin feedback.

Este patrón dual (Realtime + polling) es una buena práctica para cualquier funcionalidad crítica. Nunca dependas de un solo canal de comunicación.

¿Cómo asegurar el sistema de código QR?

La autenticación por código QR introduce vectores de ataque específicos. Aquí están las medidas implementadas en TAMSIV:

  • Expiración a los 5 minutos: un código QR no utilizado se vuelve inválido. Esto impide la reutilización de capturas de pantalla o códigos QR compartidos.
  • Uso único: una sesión solo puede confirmarse una vez. Cualquier intento posterior es rechazado.
  • Autenticación requerida en el móvil: solo un usuario conectado a la aplicación puede confirmar. El JWT se verifica en el backend como para los WebSockets.
  • Token efímero: el token generado para la web es de un solo uso y de duración limitada. Sirve únicamente para iniciar la sesión web, no como token permanente.
  • UUID v4 impredecible: el UUID utilizado para la sesión se genera con un CSPRNG (Cryptographically Secure Pseudo-Random Number Generator). Imposible de adivinar.

Estas medidas están alineadas con las recomendaciones OWASP para la autenticación.

Doble pantalla mostrando un temporizador de cuenta regresiva en un navegador web y un visor de cámara escaneando un código QR en un smartphone
El código QR se regenera automáticamente a los 4 minutos y 30 segundos con una cuenta regresiva visual para guiar al usuario.

¿Cuál es la experiencia de usuario final?

La UX ha sido cuidada hasta el más mínimo detalle:

  1. Regeneración automática del QR: a los 4 minutos y 30 segundos, el código QR se regenera automáticamente con un nuevo UUID. Una cuenta regresiva visual indica el tiempo restante. El usuario nunca tiene que actualizar la página.
  2. Animación de conexión: cuando se confirma el escaneo, una animación suave transiciona entre la página de inicio de sesión y el panel de control. Sin recarga de página.
  3. Opciones alternativas: correo electrónico/contraseña y Magic Link están disponibles debajo del código QR. Ningún usuario se queda bloqueado si el escaneo no funciona.
  4. Responsivo: en el móvil (cuando el QR no tiene sentido), la interfaz prioriza el correo electrónico/contraseña y Magic Link. El QR se muestra solo en escritorio/tablet.

El sistema de onboarding guía a los nuevos usuarios web hacia el código QR primero, con un fallback natural a los métodos clásicos.

¿Cuánto código representa esta característica?

Aproximadamente 300 líneas en el lado web (componente QR, lógica Realtime/polling, gestión de tokens) y 150 líneas en el lado móvil (escáner, verificación, llamada a la API de confirmación). Es compacto.

La razón: Supabase hace la mayor parte del trabajo. La base de datos almacena las sesiones, Realtime envía las actualizaciones, Auth gestiona los tokens. El código de la aplicación se centra en la orquestación y la UX.

Esto es típico del enfoque de arquitectura Supabase de TAMSIV: maximizar lo que la plataforma ofrece de forma nativa, minimizar el código personalizado. El mismo principio que guía la estrategia de internacionalización y el sistema de gamificación.

¿Qué alternativas al código QR existen para la autenticación entre dispositivos?

Existen otros enfoques posibles para la autenticación entre dispositivos:

  • Deep links: enviar un enlace clicable al usuario que abre la aplicación y confirma. Funciona bien, pero requiere que el usuario esté en el mismo dispositivo, lo cual no es el caso aquí.
  • Código numérico: mostrar un código de 6 dígitos que el usuario introduce en la aplicación. Más universal pero más lento (6 segundos frente a 2 segundos para un escaneo).
  • Notificación push: enviar una notificación push con un botón "Confirmar". Requiere que las notificaciones estén activadas y que el sistema FCM esté configurado.
  • WebAuthn/Passkeys: la solución moderna, pero aún no universalmente compatible en todos los dispositivos.

El código QR ofrece el mejor compromiso entre rapidez, universalidad y "efecto wow". Es el tipo de característica que hace decir "está bien pensado", y esa es exactamente la impresión que TAMSIV quiere dejar.

Preguntas Frecuentes

¿Qué sucede si cierro el navegador después de escanear el código QR?

El token generado para la sesión web se almacena en el almacenamiento local. En la próxima visita, el sitio verifica este token y te vuelve a conectar automáticamente si el token sigue siendo válido. No necesitas volver a escanear el código QR en cada visita.

¿Se pueden tener varias sesiones web al mismo tiempo?

Sí, cada escaneo crea una sesión independiente. Puedes estar conectado en tu ordenador de escritorio y tu portátil simultáneamente. Cada sesión tiene su propio token y puede ser revocada individualmente desde la configuración de la aplicación.

¿Funciona el código QR sin conexión a internet?

No, el código QR requiere una conexión a internet activa en ambos lados (móvil y web). El escaneo decodifica un UUID que debe ser verificado en línea a través de Supabase. Para uso sin conexión, los métodos de correo electrónico/contraseña siguen estando disponibles.

¿Cómo protege TAMSIV contra el phishing de códigos QR?

El código QR solo codifica un UUID de sesión, no datos sensibles. La confirmación se realiza a través de la aplicación oficial de TAMSIV, que verifica el dominio y la validez de la sesión. Un código QR falsificado redirigiría a un UUID inexistente en la base de datos y fallaría inmediatamente.

¿Por qué el código QR expira después de solo 5 minutos?

Cinco minutos es un compromiso entre seguridad y UX. Es lo suficientemente largo para que el usuario tenga tiempo de coger su teléfono y escanear. Es lo suficientemente corto para limitar la ventana de ataque si el QR es interceptado. La regeneración automática a los 4 minutos y 30 segundos garantiza un QR siempre fresco sin acción del usuario.