Error message
Error(InvalidSignature)
Also printed as
- called `Result::unwrap()` on an `Err` value: Error(InvalidSignature)
- InvalidSignature
`{:?}` prints `Error(InvalidSignature)`, `{}` prints `InvalidSignature`; `.unwrap()` panics with "called `Result::unwrap()` on an `Err` value: Error(InvalidSignature)".
jsonwebtoken (Rust crate) — ErrorKind::InvalidSignature from decode()
What it means
The `jsonwebtoken` crate parsed the token, accepted its algorithm, and the signature did not verify with the `DecodingKey` you passed. `Error(InvalidSignature)` is the `Debug` form you see in logs and `unwrap()` panics; the `Display` form is just `InvalidSignature`. The crate does not distinguish "wrong key" from "modified token" — both mean the signature is not valid for this key.
Why it happens
The DecodingKey does not belong to the signer
commonA key from another environment, a hard-coded key after the issuer rotated, or picking a JWK by position instead of by `kid`.
The token's ECDSA signature is DER-encoded
occasionalA token built by hand with a KMS or OpenSSL signature carries DER (~71 bytes) instead of the 64-byte r‖s that ES256 requires; it never verifies.
HS256 secret bytes differ
occasional`DecodingKey::from_secret(b"...")` vs `from_base64_secret("...")` on the two sides produce different keys from the same configuration string.
How to fix it
- 1.
Handle the error kind explicitly
Map `ErrorKind::InvalidSignature` to 401 and keep it distinct from expiry, so clients do not retry a token that can never pass.
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.
Select the key by kid from the issuer's JWKS
`JwkSet::find` and `DecodingKey::from_jwk` pick exactly the key the issuer names in the header.
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)?;