Rotação de refresh tokens OAuth em arquiteturas Worker
A rotação melhora a detecção de replay, mas transforma o refresh token em estado compartilhado e substituível. Em Workers serverless, requisições podem rodar em isolates diferentes sem memória compartilhada. Se dois jobs renovarem a mesma autorização, um pode invalidar o token que o outro ainda espera. A correção depende de coordenação e armazenamento durável, não de simplesmente repetir chamadas ao endpoint de token.
Publicado em 28 de setembro de 202614 min de leituraCiclo OAuth e concorrência
Serialize a renovação por autorização
Uma chamada renova; grava o token novo antes de liberar as demais
1 / RequisiçãoWorker detecta access token perto do vencimento.
2 / CoordenarAdquire exclusividade por autorização.
3 / RenovarEnvia o refresh token atual uma única vez.
4 / PersistirGrava tokens e versão de forma atômica.
5 / LiberarDemais chamadas leem a nova versão.
6 / RecuperarClassifica timeout, replay ou revogação.
Guarde a família de tokens como estado durável
Mantenha um registro por usuário ou conta conectada: refresh token criptografado, validade do access token, escopos, provedor, versão do token, estado da renovação e horário do último sucesso. Não associe o dado somente a uma instância efêmera do Worker. Proteja as chaves de criptografia separadamente e nunca escreva tokens em logs.
Use lock, lease ou single-flight por autorização. Uma segunda chamada deve aguardar e reler o registro, aproveitando o access token novo em vez de submeter novamente o refresh anterior. Use controle de versão para impedir que uma resposta atrasada sobrescreva a geração mais recente.
Trate como incerta uma resposta perdida
O servidor OAuth e seu banco geralmente não compartilham uma transação. O provedor pode invalidar o token antigo e a resposta se perder antes de você salvar o substituto. Repetir automaticamente o token antigo pode ser interpretado como replay e revogar toda a família.
Resultado
Resposta segura
Evite
Renovação e gravação concluídas
Compartilhar a versão nova
Servir token antigo em cache
Outro Worker renovou
Reler versão vencedora
Reutilizar o refresh anterior
Timeout sem saber o resultado
Marcar como incerto e seguir a política do provedor
Retry ilimitado do token antigo
Invalid grant ou sinal de replay
Parar, revogar sessão local e pedir nova autorização
Repetir silenciosamente
Alguns provedores documentam tolerância, idempotência ou recuperação; outros não. Siga o contrato específico, imponha timeout e represente “resultado incerto” explicitamente. Não invente uma estratégia universal para uma troca de credencial irreversível.
Coordene com primitives adequadas ao runtime
Workers sem estado não oferecem exclusão mútua entre isolates por memória de processo. Use armazenamento transacional ou um coordenador por autorização. Durable Objects oferecem coordenação e persistência fortemente consistente, mas requisições podem ser processadas fora da ordem de chegada; versões explícitas continuam necessárias. Banco relacional com compare-and-swap ou lock também pode funcionar conforme as garantias do runtime.
Preserve as fronteiras de segurança
Criptografe refresh tokens, limite escopos e vincule o registro ao usuário/tenant correto. Restrinja endpoints de callback e renovação e trate a sessão web separadamente. A RFC 9700 recomenda rotação ou tokens vinculados ao emissor para clientes públicos. Reutilização pode indicar comprometimento: trate como evento de segurança, não erro transitório.
Teste os caminhos de falha
Simule duas renovações simultâneas, reinício antes da gravação, timeout depois de o provedor aceitar, falha do banco e detecção de replay. Verifique que só uma troca ocorre, o token mais novo sobrevive e nenhum segredo vai para logs. Teste logout e revogação remota também.
Em resumo
Rotação transforma refresh tokens num problema de concorrência. Coordene uma renovação por autorização, persista com controle de versão, diferencie falha conhecida de resultado incerto e leve sinais de replay a sério. Computação stateless ainda exige coordenação stateful quando usar o token invalida sua versão anterior.