Quando encontro assinatura JWT inválida, não começo trocando algoritmos ou desativando verificações até algo “passar”. Preservo o token original, decodifico apenas o necessário para entender alg, kid e iss, e reconstruo o caminho até a fonte de chave que a aplicação realmente confia.
Se já tenho o secret HMAC ou a chave pública RSA esperada, uso o Verificador de Assinatura JWT sobre o token original.
O que uma assinatura inválida realmente me diz
Um JWS assinado tem:
header.payload.signature
A assinatura protege os bytes codificados do cabeçalho e payload. Se a verificação falha, pelo menos um elemento não corresponde ao que o verificador espera.
As causas que procuro primeiro são:
- secret HMAC errado;
- chave pública RSA errada;
- issuer ou tenant errado;
kidapontando para outra chave;- cache JWKS desatualizado após rotação;
- algoritmo incompatível;
- token modificado, truncado ou reformatado;
- PEM/JWK ou encoding de secret diferente entre sistemas.
1. Preservo o token original
Não edito payload para “testar” uma correção. Alterar:
{"role":"user"}
para:
{"role":"admin"}
muda os bytes assinados. Reencodar o JSON não preserva a assinatura original.
Também evito remover espaços ou recriar segmentos a partir do JSON. A assinatura cobre a representação codificada original, não uma versão semanticamente equivalente do objeto.
2. Leio alg, kid e iss
No Decodificador JWT, procuro algo como:
{
"alg": "RS256",
"kid": "key-42"
}
Uso esses valores como pistas, não como política de confiança. alg é informação fornecida pelo token. kid é uma dica de seleção. iss é uma declaração ainda não autenticada até a assinatura ser verificada.
A configuração da aplicação é que deve dizer quais algoritmos, emissores e fontes de chave são aceitos.
3. Confirmo o algoritmo esperado
Se a aplicação foi configurada para RS256, espero uma allowlist explícita que permita RS256. Não mudo para HS256 só porque o token diz alg: HS256.
A RFC 8725 recomenda restringir os algoritmos aceitos. Isso evita confusão de algoritmo e reduz o risco de transformar um problema operacional em uma falha de segurança.
4. Rastreio a chave até o emissor
Para HMAC, confirmo os bytes exatos do segredo compartilhado.
Para RSA, confirmo que a chave pública vem do emissor que a aplicação decidiu confiar.
Erros frequentes:
- token de produção verificado com chave de desenvolvimento;
- tenant errado;
- PEM sem
BEGIN/END PUBLIC KEY; - certificado fornecido quando a biblioteca espera SPKI;
- JWKS de outro issuer;
- cache de chaves antigo;
kidcorreto em um conjunto de chaves errado.
Não basta encontrar alguma chave que faça a assinatura passar. Ela precisa pertencer ao trust path correto.
5. Verifico kid e rotação
Se o token tem kid, comparo com o JWKS confiável atual.
Um kid not found costuma indicar:
- rotação recente;
- cache JWKS antigo;
- ambiente dev/prod misturado;
- issuer errado;
- lógica de seleção de chave incorreta.
O guia de JWT kid e JWKS aprofunda essa etapa. Quando já tenho o conjunto de chaves, uso o Validador JWKS para selecionar a chave compatível e verificar a assinatura.
6. Para HS256, verifico o encoding do secret
Dois sistemas podem mostrar a mesma string de configuração e ainda usar bytes diferentes.
Confiro:
- texto UTF-8 bruto versus Base64 decodificado;
- espaços e quebras de linha acidentais;
- secrets diferentes entre ambientes;
- rotação de segredo;
- secret curto ou humano demais.
A RFC 8725 alerta para secrets HMAC fracos, que podem permitir tentativa offline. Não resolvo um erro de assinatura trocando uma chave forte por uma senha curta apenas porque é mais fácil de copiar.
7. Se a assinatura passar, continuo validando
Assinatura válida não encerra o diagnóstico. Ainda verifico:
expenbf;iss;aud;- tipo do token;
- scopes e roles.
Por isso, depois da camada criptográfica, uso o Validador JWT e o Depurador JWT.
O que não faço
Evito estes “atalhos”:
- desativar verificação de assinatura;
- aceitar qualquer
algindicado pelo token; - baixar e confiar automaticamente em chave de URL controlada pelo token;
- editar o payload e esperar que a assinatura antiga funcione;
- tratar decodificação bem-sucedida como verificação bem-sucedida.
Meu checklist de assinatura inválida
- Mantenho o JWT compacto original intacto.
- Decodifico
alg,kid,isseaud. - Confirmo o algoritmo permitido pela aplicação.
- Identifico o emissor confiável e sua fonte de chaves.
- Comparo
kidcom o key set atual. - Investigo rotação, cache, ambiente e tenant.
- Em HMAC, confirmo bytes e encoding do secret.
- Em RSA, confirmo formato e procedência da chave pública.
- Executo a verificação com material de chave confiável.
- Se a assinatura passa mas a API ainda retorna 401, sigo para issuer, audience e tempo.
Uma assinatura inválida não é um detalhe de parsing. Para mim, ela significa que o verificador ainda não conseguiu estabelecer integridade e autenticidade com a chave que recebeu; a solução está no caminho de chave, algoritmo ou confiança, não em ignorar a falha.