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.
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:
- 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".
- Exibição: o QR code codifica esse UUID. O site se inscreve no canal Supabase Realtime para esta sessão.
- Escaneamento: o usuário escaneia o QR code com o aplicativo móvel TAMSIV. O aplicativo decodifica o UUID.
- 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".
- 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.
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.
Qual é a experiência final do usuário?
A UX foi cuidadosamente elaborada nos mínimos detalhes:
- 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.
- 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.
- 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.
- 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.