OAuth PKCE Verifier + Challenge
Gere um par OAuth PKCE (code_verifier e code_challenge S256) para fluxos de autenticação seguros em apps móveis e SPAs. Mitiga ataques de interceptação de código.
verifier + challenge
—
O que é PKCE e por que existe
PKCE (Proof Key for Code Exchange, pronuncia-se "pixy") é a extensão do OAuth 2.0 descrita na RFC 7636 (2015) que protege o fluxo de Authorization Code para clientes que não conseguem manter um segredo — ou seja, aplicativos mobile nativos, apps de desktop e SPAs. Em um cliente confidencial clássico o servidor guarda um client_secret embutido em um backend que o usuário nunca vê, e é esse segredo que prova ao endpoint de token que a troca do authorization code é legítima. Clientes públicos não têm onde esconder nada: o que vai dentro do binário pode ser extraído, o que vai em JavaScript fica visível no DevTools. PKCE substitui o client secret estático por uma prova por requisição.
Sem PKCE, um cliente público fica exposto ao ataque de interceptação de código: um aplicativo malicioso registrado no mesmo esquema de URL custom, ou uma extensão de browser comprometida, captura o authorization code do redirect e troca por tokens antes do app legítimo. Com PKCE, conhecer o código não basta — o atacante também precisaria do verifier, que nunca saiu do cliente original.
O protocolo verifier / challenge
- O cliente gera um code_verifier: string aleatória de alta entropia com 43 a 128 caracteres do conjunto unreserved
[A-Z a-z 0-9 - . _ ~]. Aproximadamente 32 bytes de CSPRNG codificados em base64url dão 43 caracteres e ~256 bits de entropia — o mínimo recomendado. - O cliente deriva o code_challenge =
BASE64URL(SHA256(verifier))comcode_challenge_method=S256. O métodoplain(challenge = verifier) é permitido pela RFC mas desencorajado, e proibido no OAuth 2.1. - O cliente envia
code_challengeem/authorize; o authorization server vincula o challenge ao código emitido. - Em seguida o cliente chama
/tokencom o código e o verifier original; o servidor confereSHA256(verifier) == challenge_armazenadoantes de emitir tokens.
Notas de implementação
O verifier precisa ser único por requisição de autorização — reusar entre fluxos destrói a prova e permitiria casar um challenge vazado com um código novo. Mantenha em memória ou em sessionStorage com TTL curto; nunca persista por longo prazo e nunca envie pelo front channel. Bibliotecas maduras (oidc-client-ts, AppAuth iOS/Android, pkce-challenge no npm, authlib em Python) cuidam do pareamento para você. PKCE não substitui HTTPS — os dois lados do fluxo continuam tendo que rodar sobre TLS, caso contrário um atacante na rede lê tudo de qualquer jeito.
PKCE vs parâmetro state
PKCE às vezes é confundido com o parâmetro state do OAuth, mas eles resolvem problemas diferentes. state é um token CSRF: vincula a requisição /authorize ao callback subsequente para que um atacante não engane a vítima a completar o fluxo de outra pessoa. PKCE vincula a troca por token ao iniciador original: mesmo com um código roubado, não há como trocar por token sem o verifier. Você quer os dois em todo fluxo de cliente público — são complementares, não alternativas.
Perguntas frequentes
Preciso de PKCE em um app web com backend que já tem client_secret? A RFC 7636 original marca como MUST para clientes públicos e RECOMMENDED para clientes confidenciais. O draft do OAuth 2.1 promove para MUST em todos os clientes independentemente do tipo, porque o custo marginal é desprezível e a defesa é genuinamente útil.
S256 ou plain? Sempre S256. O método plain só existe para dispositivos embarcados legados que não conseguem calcular SHA-256, o que em 2026 é essencialmente nada. A maioria dos authorization servers recusa plain diretamente.
Posso reusar o mesmo verifier? Não. Toda a garantia colapsa se o verifier for previsível ou repetido. Gere um novo valor aleatório de 32 bytes para cada chamada a /authorize.
E se o usuário abrir duas abas do mesmo app ao mesmo tempo? Cada aba precisa de seu próprio verifier; vincule por state ou por aba no storage, senão a segunda troca falha.
O verifier gerado aqui é enviado para algum lugar? Não. Tanto o verifier quanto o challenge são calculados no seu navegador via crypto.getRandomValues() e SubtleCrypto.digest — nada é enviado para um servidor.
Ferramentas Relacionadas
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 OAuth State
Gera tokens state aleatórios seguros (128 bits) para proteção CSRF em fluxos OAuth 2.0. Recomendado pela RFC 6749.
Gerador de JWT Aleatório (Fake)
Gera JWT com header/payload/signature aleatórios (sem assinatura válida) para mockar fluxos OAuth em desenvolvimento local.