Gerador OAuth State
Gera tokens state aleatórios seguros (128 bits) para proteção CSRF em fluxos OAuth 2.0. Recomendado pela RFC 6749.
—
State OAuth assinado: codificando intenção dentro do parâmetro
Existem duas escolas para o parâmetro state do OAuth 2.0. A abordagem aleatória opaca gera uma string de alta entropia, armazena no servidor e compara no callback. A abordagem signed claims embute dados estruturados — nonce anti-CSRF, URL de retorno, intenção do usuário, variante A/B — dentro do próprio state e prova integridade com um HMAC. Ambas previnem CSRF; o state assinado adicionalmente permite que o callback reconstrua contexto sem armazenamento de sessão, o que é decisivo para runtimes serverless e edge (Cloudflare Workers, Vercel Edge, AWS Lambda) onde sessões sticky são caras ou impossíveis.
Um layout típico de state assinado codifica um payload JSON e anexa uma tag HMAC-SHA256, separados por um ponto:
payload = base64url(JSON.stringify({
csrf: random(16), // nonce anti-CSRF
return_url: "/dashboard",
intent: "signup", // signup | login | link
variant: "B", // braço do A/B test
iat: 1716902400, // issued-at (unix)
ttl: 600 // 10 minutos
}))
tag = base64url(HMAC_SHA256(STATE_SECRET, payload))
state = payload + "." + tag
Fluxo de validação no callback
Faça split pelo ponto, recompute o HMAC sobre o payload e compare em tempo constante (crypto.timingSafeEqual). Só depois da tag bater, faça parse do JSON. Em seguida cheque iat + ttl > agora para impor janela de 5-10 minutos — curta o bastante para derrotar replay, longa o bastante para usuários legítimos em rede instável. Rejeite tudo mais velho. Por fim, valide return_url contra uma allowlist de caminhos do mesmo origin para evitar open redirect.
JWT vs HMAC custom
Você pode usar um JWT (jsonwebtoken, jose) para o mesmo papel — as claims exp/iat e assinatura HS256 mapeiam direto em state assinado. JWT é overkill para um valor que vive 10 minutos: o header adiciona bytes e os footguns de algorithm confusion ("alg":"none") são reais. HMAC custom mantém o state mais curto para o orçamento de URL e evita parsers surpresa. libsodium / tweetnacl oferecem crypto_auth se quiser HMAC fora da stdlib.
Higiene e rotação de segredo
Escolha um segredo de 256 bits (32 bytes aleatórios), guarde na variável de ambiente STATE_SECRET, nunca commit no git. Faça rotação mantendo um pequeno keyring — segredo atual e anterior — verificando contra qualquer chave ativa dentro da janela de TTL. Após rotacionar, a chave antiga pode ser aposentada em 10 minutos já que nenhum state em voo sobrevive ao TTL. OAuth 2.1 ainda recomenda state ao lado do PKCE (agora obrigatório); defendem camadas diferentes.
FAQ
Prefiro state assinado a store no servidor? Sim se você é stateless (serverless, edge). Não se já mantém session store — state aleatório é mais simples e fica opaco.
HMAC-SHA256 é forte o bastante? Sim — com segredo de 256 bits é a mesma primitiva por trás de HS256 JWTs, AWS request signing e TLS PRFs. O elo fraco é a disciplina de rotação, não o algoritmo.
Qual TTL ideal? 5-10 minutos para fluxos interativos. Janelas maiores vazam por redirects e shoulder-surfing; menores derrubam usuários reais em rede ruim.
State assinado dispensa PKCE? Não. PKCE liga o authorization code ao cliente original; state assinado defende a URL de callback contra CSRF. Mitigam ataques diferentes e OAuth 2.1 exige ambos para clientes públicos.
Ferramentas Relacionadas
OAuth State CSRF Token
Gera valor "state" criptograficamente aleatório (32 bytes base64url) para mitigar CSRF.
Gerador JWKS EC (P-256/P-384/P-521)
Gera JWKS (JSON Web Key Set) com chave EC (P-256/P-384/P-521) pronta para endpoint /.well-known/jwks.json, com kid e use.
Gerador de CSRF Token
Gera tokens CSRF aleatórios (32 bytes) em hex ou base64url, usando a Crypto API do navegador. Pronto para colar.