Mensagem de erro
Error(InvalidSignature)
Também aparece como
- called `Result::unwrap()` on an `Err` value: Error(InvalidSignature)
- InvalidSignature
`{:?}` imprime `Error(InvalidSignature)`, `{}` imprime `InvalidSignature`; `.unwrap()` entra em panic com “called `Result::unwrap()` on an `Err` value: Error(InvalidSignature)”.
jsonwebtoken (Rust crate) — ErrorKind::InvalidSignature from decode()
O que significa
O crate `jsonwebtoken` analisou o token, aceitou o algoritmo, e a assinatura não passou na verificação com a `DecodingKey` que você forneceu. `Error(InvalidSignature)` é a forma `Debug` que aparece nos logs e nos panics de `unwrap()`; a forma `Display` é só `InvalidSignature`. O crate não distingue “chave errada” de “token modificado” — os dois significam que a assinatura não é válida para esta chave.
Por que acontece
A DecodingKey não pertence ao signatário
comumUma chave de outro ambiente, uma chave fixa no código depois que o emissor fez a rotação, ou a escolha de uma JWK pela posição em vez de pelo `kid`.
A assinatura ECDSA do token está em codificação DER
ocasionalUm token montado à mão com uma assinatura de KMS ou do OpenSSL traz DER (~71 bytes) em vez dos 64 bytes de r‖s que o ES256 exige; ele nunca passa na verificação.
Os bytes do segredo HS256 são diferentes
ocasional`DecodingKey::from_secret(b"...")` de um lado e `from_base64_secret("...")` do outro produzem chaves diferentes a partir da mesma string de configuração.
Como corrigir
- 1.
Tratar o tipo de erro explicitamente
Mapeie `ErrorKind::InvalidSignature` para 401 e mantenha esse caso separado da expiração, para que os clientes não tentem de novo com um token que nunca vai passar.
rust use jsonwebtoken::errors::ErrorKind; match decode::<Claims>(&token, &key, &validation) { Ok(data) => Ok(data.claims), Err(e) => match e.kind() { ErrorKind::InvalidSignature => Err(AuthError::Unauthorized), // wrong key or tampered token ErrorKind::ExpiredSignature => Err(AuthError::Expired), _ => Err(AuthError::BadToken), }, } - 2.
Escolher a chave pelo kid no JWKS do emissor
`JwkSet::find` e `DecodingKey::from_jwk` escolhem exatamente a chave que o emissor indica no cabeçalho.
rust use jsonwebtoken::{decode_header, jwk::JwkSet, DecodingKey}; let header = decode_header(&token)?; let kid = header.kid.ok_or(AuthError::BadToken)?; let jwk = jwks.find(&kid).ok_or(AuthError::UnknownKey)?; // jwks: JwkSet fetched from the issuer let key = DecodingKey::from_jwk(jwk)?;