Mensagem de erro
TypeError: "ES256" signatures must be "64" bytes, saw "71"
Também aparece como
- "ES256" signatures must be "64" bytes, saw "70"
- "ES256" signatures must be "64" bytes, saw "72"
- "ES384" signatures must be "96" bytes, saw "103"
- "ES512" signatures must be "132" bytes, saw "139"
O número após “saw” varia entre 70 e 72 para ES256 (o comprimento do DER depende dos bits iniciais de r e s); ES384 espera 96 bytes, e ES512, 132. O erro é um `TypeError` simples, não um `JsonWebTokenError`, então verificações com `instanceof` para os erros do jsonwebtoken não o capturam.
jsonwebtoken / jws / jwa (Node.js) — TypeError from ecdsa-sig-formatter
O que significa
O segmento de assinatura do token decodifica para 71 bytes, mas uma assinatura JWS ES256 precisa ter exatamente 64 bytes: a concatenação bruta r‖s definida na RFC 7518 §3.4. Um valor de 70 a 72 bytes que começa com `0x30` é a codificação ASN.1 DER da mesma assinatura — o formato que OpenSSL, Java, serviços de KMS e o `crypto.sign()` do Node produzem por padrão. O token foi gerado por um signatário que pulou a conversão de DER para bruto; o jsonwebtoken (por meio do ecdsa-sig-formatter) o rejeita antes de qualquer verificação.
Por que acontece
Um signatário implementado à mão emitiu DER
comumUm código que monta o JWT por conta própria e assina com `crypto.sign("sha256", data, key)` ou `createSign().sign(key)` recebe saída em DER, a menos que passe `dsaEncoding: "ieee-p1363"`. O token parece correto em todo lugar até que um verificador que segue o padrão confira o comprimento.
Um KMS ou HSM assinou o token
comumO `Sign` do AWS KMS e o `asymmetricSign` do Google Cloud KMS retornam assinaturas ECDSA em DER, então assinar JWTs com eles exige uma etapa explícita de conversão. (O Azure Key Vault e o `CKM_ECDSA` do PKCS#11 já retornam r‖s bruto — confira o que a documentação do seu provedor diz antes de converter.)
A codificação padrão de outra linguagem
ocasionalO `SHA256withECDSA` do Java, o `sign()` da biblioteca cryptography do Python, o `ecdsa.SignASN1` do Go e a CLI do OpenSSL produzem DER. Bibliotecas feitas para JOSE convertem automaticamente; chamadas criptográficas genéricas, não.
O segmento de assinatura está corrompido
raraSe o comprimento informado não estiver na faixa de 70 a 72 (por exemplo, “saw 2”), o terceiro segmento foi truncado ou substituído, e não codificado de outra forma.
Como corrigir
- 1.
Pedir r‖s bruto ao node:crypto
`dsaEncoding: "ieee-p1363"` faz o Node emitir o formato de comprimento fixo que o JWS exige. Melhor ainda: assine com uma biblioteca JOSE (o `jwt.sign` do jsonwebtoken, o `SignJWT` do jose), que faz isso por você.
js import { sign } from "node:crypto"; const signature = sign("sha256", Buffer.from(signingInput), { key: privateKey, dsaEncoding: "ieee-p1363", // raw r||s: 64 bytes for P-256, as RFC 7518 §3.4 requires }); const token = signingInput + "." + signature.toString("base64url"); - 2.
Converter o DER de um KMS antes de montar o token
O `ecdsa-sig-formatter` (instalado com o jsonwebtoken por meio de jws/jwa) converte DER para o formato JOSE. O conversor DER ⇄ bruto mostra r e s nas duas formas para que você confirme a conversão.
js import ecdsaSigFormatter from "ecdsa-sig-formatter"; // AWS KMS and Google Cloud KMS return DER; convert once before assembling the JWS. const derSignature = Buffer.from(kmsResponse.Signature); const joseSignature = ecdsaSigFormatter.derToJose(derSignature, "ES256"); // base64url, 64 bytes decoded const token = signingInput + "." + joseSignature;