Tokens de recuperação, confirmação e convite precisam ser imprevisíveis. O módulo secrets usa a fonte segura de aleatoriedade do sistema operacional e deve ser preferido a random para autenticação.

Gerar um token para URL

import hashlib
import secrets
from datetime import UTC, datetime, timedelta

token = secrets.token_urlsafe(32)
token_hash = hashlib.sha256(token.encode()).hexdigest()
expira_em = datetime.now(UTC) + timedelta(minutes=20)

Envie o token original ao usuário uma vez e armazene apenas token_hash, finalidade, usuário e expiração. Quando ele voltar, calcule o hash e procure um registro ainda válido. Marque como usado dentro da mesma transação da alteração protegida.

Não registre o token, não o inclua em analytics e evite que a URL vaze por cabeçalho Referer. Use HTTPS e limite tentativas. O artigo sobre segurança de APIs reúne outros controles.

Comparar e definir validade

secrets.compare_digest() reduz diferenças de tempo na comparação direta de valores. Em um fluxo baseado em busca por hash, o banco já decide a correspondência, mas comparação constante continua útil em outros protocolos.

O tamanho necessário depende do cenário. Passe explicitamente bytes suficientes em vez de depender para sempre do padrão, que a documentação permite alterar. Tokens não substituem senha com hash adequado, MFA, expiração ou revogação.

A documentação oficial de secrets, consultada em 22 de julho de 2026, descreve token_bytes, token_hex, token_urlsafe e compare_digest. Segurança vem do fluxo completo, não apenas de gerar uma string aleatória.

Por que random não serve

O módulo random produz sequências pseudoaleatórias para simulação e amostragem. Seu estado pode ser reconstruído quando um atacante conhece saídas suficientes, e uma semente baseada em horário reduz o espaço de busca. Por isso, ele não serve para recuperação de senha, chaves de API, cookies de sessão, convites ou nonces.

secrets delega a geração à fonte criptograficamente segura do sistema operacional. A API compacta evita escolhas frágeis de sementes e algoritmos. Ela não protege todo o fluxo: expiração, armazenamento, transporte e autorização continuam sob responsabilidade da aplicação.

Escolher a representação

token_bytes(n) devolve bytes para protocolos ou processamento interno. token_hex(n) representa cada byte com dois caracteres hexadecimais, portanto 32 bytes produzem 64 caracteres. token_urlsafe(n) usa Base64 compatível com URL e gera aproximadamente 1,3 caractere por byte.

O argumento indica bytes, não o comprimento final do texto. Escolha-o explicitamente e documente o modelo de ameaça. Trinta e dois bytes oferecem margem ampla para muitos tokens online de alto valor, embora requisitos regulatórios possam exigir outra decisão.

valor_binario = secrets.token_bytes(32)
valor_hex = secrets.token_hex(32)
valor_url = secrets.token_urlsafe(32)

Não corte a saída para caber em uma coluna curta, pois o corte remove entropia. Ajuste o schema e valide os limites da URL, do cabeçalho ou do campo que transportará o valor.

Projetar o ciclo de recuperação

Responda de forma equivalente para contas existentes e inexistentes, reduzindo enumeração de usuários. Se a conta existir, gere o token, calcule seu resumo e registre finalidade, usuário, expiração e estado de uso. Envie o original uma única vez pelo canal previsto.

Na confirmação, rejeite entrada excessiva ou malformada antes da consulta. Calcule o mesmo resumo e valide finalidade, usuário, expiração e ausência de uso. Altere a senha e marque o token como consumido na mesma transação. Revogue sessões existentes quando a política do produto exigir.

def resumir_token(valor: str) -> str:
    return hashlib.sha256(valor.encode("utf-8")).hexdigest()


def expirou(instante: datetime, agora: datetime) -> bool:
    return instante <= agora

Um hash rápido pode resumir um token aleatório de alta entropia porque não há segredo humano fraco para adivinhar. Senhas exigem algoritmos próprios, lentos e configuráveis, como Argon2, scrypt ou bcrypt.

Evitar vazamento no transporte

Use HTTPS em todo o fluxo. Tokens na query string podem aparecer no histórico, em logs de proxy, monitoramento e cabeçalhos de referência. A página de confirmação pode trocar o token por estado temporário no servidor e redirecionar para uma URL limpa. Aplique política de referrer restritiva e evite recursos de terceiros nessa página.

Nunca coloque o valor em erros, métricas ou traces. Mascaramento central ajuda, mas o código deve evitar registrá-lo. Limite tentativas por conta, origem e token sem criar negação de serviço fácil contra a vítima. Alertas devem registrar anomalias sem conservar credenciais.

Comparar valores e criar códigos curtos

secrets.compare_digest(a, b) reduz variações de tempo relacionadas ao conteúdo ao comparar valores do mesmo tipo. É útil para MACs, resumos e segredos curtos disponíveis na aplicação. A comparação constante não corrige diferenças anteriores, como mensagens que revelam a existência de uma conta.

Quando um canal exige código numérico, secrets.randbelow() evita viés de transformações improvisadas:

codigo = f"{secrets.randbelow(1_000_000):06d}"

Um código de seis dígitos possui somente um milhão de possibilidades. Ele precisa de vida curta, limite rígido de tentativas e vínculo com usuário e finalidade. secrets.choice() seleciona caracteres com segurança, mas o espaço resultante ainda precisa ser suficiente.

Testar sem enfraquecer produção

Testes não devem esperar uma saída exata de secrets. Verifique formato, comprimento aproximado e ciclo de vida. Injete o relógio para testar expiração. Se um teste de persistência precisar de valor conhecido, substitua o gerador no limite da aplicação; nunca introduza uma semente previsível em produção.

Teste concorrência. Duas confirmações simultâneas não podem consumir o mesmo token, então o banco precisa de atualização atômica ou restrição. Cubra valores expirados, finalidade ou usuário incorretos, entrada excessiva e registro já consumido. Esses casos avaliam as propriedades importantes, não uma amostra aleatória.

Checklist antes de colocar em produção

Registre em documentação interna quem pode emitir, validar e revogar cada tipo de token. Finalidades diferentes devem usar registros ou prefixos distinguíveis, evitando que um convite seja aceito como recuperação de senha. Confirme que o servidor valida o usuário associado, não apenas a existência do resumo.

Verifique o relógio e use instantes com fuso explícito. Defina expiração no servidor, nunca a partir de um valor enviado pelo cliente. Limpe registros vencidos por uma rotina controlada, mantendo somente dados necessários para auditoria e respeitando a política de retenção.

Faça uma inspeção dos caminhos de observabilidade: servidor web, proxy, provedor de e-mail, monitoramento de erros e analytics. O token não deve aparecer em nenhum deles. Revise ainda cabeçalhos de cache, redirecionamentos e páginas de erro. Por último, documente como agir se houver vazamento: revogação em massa, comunicação, rotação das chaves relacionadas e evidências mínimas para investigação.

Repita essa revisão quando o canal de entrega, o provedor ou o formato da URL mudar. Uma alteração operacional aparentemente pequena pode criar um novo local de exposição.