Blog
Feature
6 de fevereiro de 20269 min

Autenticação por QR code: o padrão WhatsApp Web com Supabase

Para conectar o site à aplicação móvel, eu queria algo instantâneo. Sem formulários, sem necessidade de digitar a senha novamente. O padrão WhatsApp Web: escanear um QR code e pronto, conectado. Veja como implementei este sistema no TAMSIV com Supabase Realtime, um fallback de polling e uma UX que impressiona.

Pontos chave a reter:
- O QR code codifica um UUID de sessão único — o site se inscreve em tempo real via Supabase Realtime.
- Um fallback de polling HTTP (a cada 2s) assume se o Realtime falhar após 3 segundos.
- O QR code expira após 5 minutos e se regenera automaticamente aos 4min30 com contagem regressiva visual.
- Todo o sistema consiste em 300 linhas no lado web e 150 no lado móvel.

Por que escolher a autenticação por QR code em vez de um formulário clássico?

A autenticação clássica — e-mail + senha — funciona. Mas ela cria atrito. O usuário já tem uma conta no aplicativo móvel. Pedir para ele digitar suas credenciais novamente na web é obrigá-lo a lembrar de uma senha, potencialmente procurar em seu gerenciador e arriscar uma falha.

O QR code elimina esse atrito. O usuário já está autenticado em seu telefone. Escanear um código leva 2 segundos. É o padrão popularizado pelo WhatsApp Web, Telegram e Discord. Os usuários o conhecem e o esperam.

Para o TAMSIV, isso é ainda mais relevante, pois o site serve como um complemento ao aplicativo móvel — não como um substituto. O QR code materializa essa ligação entre as duas plataformas.

Pessoa escaneando um QR code exibido em uma tela de laptop com seu smartphone para fazer login
Escanear um QR code leva 2 segundos — contra 30 segundos para um formulário de e-mail/senha.

Como funciona o fluxo de autenticação por QR code?

Do ponto de vista do usuário, é mágico: eu escaneio, estou conectado. Do ponto de vista técnico, é um balé preciso de tokens e canais em tempo real. Aqui estão os passos:

  1. Geração: o usuário abre tamsiv.com. O site gera um UUID de sessão único e cria uma entrada no Supabase com o status "pending".
  2. Exibição: o QR code codifica esse UUID. O site se inscreve no canal Supabase Realtime para esta sessão.
  3. Escaneamento: o usuário escaneia o QR code com o aplicativo móvel TAMSIV. O aplicativo decodifica o UUID.
  4. Confirmação: o aplicativo envia seu JWT existente + o UUID para o backend. O backend verifica o JWT, gera um token de autenticação web e atualiza a sessão para "confirmed".
  5. Conexão: o site recebe a atualização via Realtime, recupera o token e o usuário é conectado.

Este fluxo garante que apenas um usuário já autenticado no aplicativo móvel possa confirmar a sessão. O token gerado para a web tem uma vida útil limitada e é independente do token móvel — as duas sessões são separadas.

Como o Supabase Realtime permite a conexão instantânea?

Supabase Realtime é o componente que torna a experiência instantânea. Quando o aplicativo móvel confirma a sessão, a mudança no banco de dados é detectada pelo canal Realtime e enviada para o navegador — em poucos milissegundos.

Tecnicamente, o site se inscreve em um canal específico filtrando pelo UUID da sessão:

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

O callback é acionado assim que o status muda de "pending" para "confirmed". O token de autenticação é incluído na atualização. O usuário vê a página de login se transformar em um painel — sem nenhuma ação adicional.

É o mesmo mecanismo Realtime que uso para o cache de conteúdo e as atualizações ao vivo em grupos colaborativos.

Diagrama arquitetural mostrando o fluxo de autenticação em tempo real entre um aplicativo móvel e um navegador web
O fluxo completo: geração do QR, escaneamento móvel, confirmação via JWT, conexão web via Realtime.

Por que um fallback de polling é indispensável?

O Supabase Realtime funciona muito bem na maioria dos casos. Mas "a maioria" não é suficiente para um recurso de autenticação. Algumas redes corporativas bloqueiam WebSockets. Alguns proxies os interrompem. Alguns navegadores têm bugs específicos.

Implementei um fallback de polling HTTP que assume automaticamente:

  • O site tenta a conexão Realtime por 3 segundos
  • Se a conexão falhar, ele muda silenciosamente para um polling HTTP a cada 2 segundos
  • O polling consulta diretamente o banco de dados: "a sessão UUID está confirmada?"
  • O usuário nunca sabe qual mecanismo está sendo usado — a experiência é idêntica

O atraso de 3 segundos é um compromisso entre reatividade e confiabilidade. Mais curto, mudaríamos muito rapidamente para o polling (menos eficiente). Mais longo, o usuário esperaria sem feedback.

Este padrão dual (Realtime + polling) é uma boa prática para qualquer funcionalidade crítica. Nunca dependa de um único canal de comunicação.

Como proteger o sistema de QR code?

A autenticação por QR code introduz vetores de ataque específicos. Aqui estão as medidas implementadas no TAMSIV:

  • Expiração em 5 minutos: um QR code não utilizado torna-se inválido. Isso impede a reutilização de capturas de tela ou QR codes compartilhados.
  • Uso único: uma sessão só pode ser confirmada uma vez. Qualquer tentativa subsequente é rejeitada.
  • Autenticação necessária no lado móvel: apenas um usuário conectado ao aplicativo pode confirmar. O JWT é verificado no backend, assim como para WebSockets.
  • Token efêmero: o token gerado para a web é de uso único e tem duração limitada. Ele serve apenas para iniciar a sessão web, não como um token permanente.
  • UUID v4 imprevisível: o UUID usado para a sessão é gerado com um CSPRNG (Cryptographically Secure Pseudo-Random Number Generator). Impossível de adivinhar.

Essas medidas estão alinhadas com as recomendações OWASP para autenticação.

Tela dupla mostrando um temporizador de contagem regressiva em um navegador web e um visor de câmera escaneando um QR code em um smartphone
O QR code se regenera automaticamente aos 4min30 com uma contagem regressiva visual para guiar o usuário.

Qual é a experiência final do usuário?

A UX foi cuidadosamente elaborada nos mínimos detalhes:

  1. Auto-regeneração do QR: aos 4min30, o QR code se regenera automaticamente com um novo UUID. Uma contagem regressiva visual indica o tempo restante. O usuário nunca precisa atualizar a página.
  2. Animação de conexão: quando o escaneamento é confirmado, uma animação suave transiciona entre a página de login e o painel. Sem recarregar a página.
  3. Opções alternativas: e-mail/senha e Magic Link estão disponíveis abaixo do QR code. Nenhum usuário é bloqueado se o escaneamento não funcionar.
  4. Responsivo: no celular (quando o QR não faz sentido), a interface prioriza e-mail/senha e Magic Link. O QR é exibido apenas em desktop/tablet.

O sistema de onboarding guia os novos usuários da web para o QR code primeiro, com um fallback natural para os métodos clássicos.

Quanto código essa funcionalidade representa?

Cerca de 300 linhas no lado web (componente QR, lógica Realtime/polling, gerenciamento de tokens) e 150 linhas no lado móvel (scanner, verificação, chamada de API de confirmação). É compacto.

A razão: o Supabase faz a maior parte do trabalho. O banco de dados armazena as sessões, o Realtime envia as atualizações, o Auth gerencia os tokens. O código do aplicativo se concentra na orquestração e na UX.

Isso é típico da abordagem de arquitetura Supabase do TAMSIV: maximizar o que a plataforma oferece nativamente, minimizar o código customizado. O mesmo princípio que guia a estratégia de internacionalização e o sistema de gamificação.

Quais alternativas ao QR code existem para a autenticação entre dispositivos?

Outras abordagens são possíveis para a autenticação entre dispositivos:

  • Deep links: enviar um link clicável ao usuário que abre o aplicativo e confirma. Funciona bem, mas exige que o usuário esteja no mesmo dispositivo — o que não é o caso aqui.
  • Código numérico: exibir um código de 6 dígitos que o usuário digita no aplicativo. Mais universal, mas mais lento (6 segundos vs 2 segundos para um escaneamento).
  • Notificação push: enviar uma notificação push com um botão "Confirmar". Exige que as notificações estejam ativadas e que o sistema FCM esteja configurado.
  • WebAuthn/Passkeys: a solução moderna, mas ainda não universalmente suportada em todos os dispositivos.

O QR code oferece o melhor compromisso entre velocidade, universalidade e "efeito uau". É o tipo de recurso que faz você dizer "isso foi bem pensado" — e é exatamente a impressão que o TAMSIV quer deixar.

FAQ

O que acontece se eu fechar o navegador depois de escanear o QR code?

O token gerado para a sessão web é armazenado no local storage. Na próxima visita, o site verifica esse token e te reconecta automaticamente se o token ainda for válido. Você não precisa escanear o QR code novamente a cada visita.

É possível ter várias sessões web ao mesmo tempo?

Sim, cada escaneamento cria uma sessão independente. Você pode estar conectado no seu computador de mesa e no seu laptop simultaneamente. Cada sessão tem seu próprio token e pode ser revogada individualmente nas configurações do aplicativo.

O QR code funciona sem conexão com a internet?

Não, o QR code requer uma conexão ativa com a internet em ambos os lados (móvel e web). O escaneamento decodifica um UUID que deve ser verificado online via Supabase. Para uso offline, os métodos de e-mail/senha permanecem disponíveis.

Como o TAMSIV protege contra o phishing de QR code?

O QR code codifica apenas um UUID de sessão — sem dados sensíveis. A confirmação é feita através do aplicativo oficial TAMSIV, que verifica o domínio e a validade da sessão. Um QR code forjado redirecionaria para um UUID inexistente no banco de dados e falharia imediatamente.

Por que o QR code expira após apenas 5 minutos?

Cinco minutos é um compromisso entre segurança e UX. É tempo suficiente para o usuário pegar o telefone e escanear. É curto o suficiente para limitar a janela de ataque se o QR for interceptado. A regeneração automática aos 4min30 garante um QR sempre fresco sem ação do usuário.