A TrendVidStream moveu toda a sua stack de autenticação para um sistema de refresh tokens rotativos que detecta um token roubado no momento em que ele é reutilizado. A mudança transformou um JWT de 30 dias, que antes permitia que um invasor navegasse livremente, em uma credencial de curta duração que aciona instantaneamente um bloqueio.

Uma única violação forçou a mudança: um SDK de um parceiro armazenou em cache um JWT de 30 dias em texto simples, um invasor o extraiu e o replicou de outro país, e o único remédio foi rotacionar a chave de assinatura — uma operação que deslogou todos os usuários. O incidente remodelou a segurança de tokens da empresa e agora impulsiona o serviço de streaming de vídeo.

Por que o modelo antigo falhou

JWTs (JSON Web Tokens) são blobs assinados e autocontidos que permitem que um servidor verifique uma requisição sem uma consulta ao banco de dados. A conveniência esconde um custo: se um token dura semanas, roubá-lo concede ao adversário semanas de acesso. Na violação, o token roubado permaneceu válido até sua expiração de 30 dias porque não havia como invalidá-lo antecipadamente.

Rotacionar a chave de assinatura é a única maneira global de invalidar todos os tokens, mas isso força cada usuário a fazer login novamente, interrompendo o serviço e erodindo a confiança. A falha não estava no JWT em si, mas em confiar em uma única credencial de longa duração.

O novo design em poucas palavras

A TrendVidStream agora emite dois tipos de tokens:

  • Access tokens – válidos por 15 minutos; eles carregam as permissões necessárias para cada chamada de API.
  • Refresh tokens – tokens de uso único que trocam um token de acesso de curta duração por um novo par.

Quando um cliente apresenta um refresh token, o servidor:

  1. Verifica a assinatura e os claims do token.
  2. Verifica se o token já foi usado.
  3. Se a verificação passar, emite um novo refresh token e um novo access token de 15 minutos.
  4. Marca o antigo refresh token como usado.

Se a etapa 2 falhar — ou seja, se o mesmo token aparecer uma segunda vez — o servidor o trata como um sinal de roubo e revoga toda a “família” de tokens vinculada àquela sessão de login. Tanto a vítima quanto o invasor são forçados a fazer login novamente, interrompendo a violação rapidamente.

Rastreando famílias de tokens

Em vez de tratar cada token como um registro isolado, o sistema os agrupa em famílias que começam quando um usuário faz login. Cada rotação cria um novo membro dessa família. O esquema SQLite usado em produção armazena:

  • family_id – um identificador estável para toda a sessão.
  • token_id – um identificador único para cada refresh token.
  • generation – um contador útil para depuração.
  • used_at – timestamp de quando o token foi resgatado.
  • revoked – uma flag que, quando definida, desativa toda a família.

Quando um evento de reutilização é detectado, a flag revoked para aquele family_id é definida, invalidando instantaneamente todos os tokens pertencentes à sessão comprometida. Isso transforma um sequestro silencioso em um alerta de alto sinal que aparece nos logs.

Três regras de implementação que mantêm o sistema confiável

  1. Valide a assinatura primeiro Um invasor poderia adivinhar IDs de tokens e disparar revogações em massa se o servidor verificar “já foi usado?” antes de validar a assinatura. Confirmar a autenticidade primeiro evita ataques de negação de serviço desnecessários.

  2. Permita uma janela de tolerância (grace window) Aplicativos móveis costumam disparar duas requisições de refresh em rápida sucessão quando um token expira. Se o servidor for rigoroso demais, a segunda requisição seria marcada como reutilização, deslogando um usuário legítimo. Alguns segundos de buffer permitem que um token “usado” ainda retorne um novo par, suavizando condições de corrida (race conditions).

  3. Envolva todo o fluxo em uma transação com bloqueio de linha (row locking) Sem atomicidade, duas requisições simultâneas poderiam pensar que ambas são as primeiras a usar um token, emitindo refresh tokens duplicados e quebrando a garantia de uso único. Uma transação de banco de dados que bloqueia a linha do token garante que apenas uma requisição tenha sucesso.

Conclusão: Ao tornar os refresh tokens de uso único e monitorar a reutilização, um sistema pode transformar cada credencial roubada em um alarme, protegendo os usuários sem forçar um logout em toda a plataforma.