Error message
Signed JWT rejected: Invalid signature
Also printed as
- com.nimbusds.jose.proc.BadJWSException: Signed JWT rejected: Invalid signature
- org.springframework.security.oauth2.jwt.BadJwtException: An error occurred while attempting to decode the Jwt: Signed JWT rejected: Invalid signature
Nimbus JOSE + JWT (Java) — BadJWSException from DefaultJWTProcessor; also surfaced by Spring Security's NimbusJwtDecoder
What it means
Nimbus selected one or more candidate keys for the token (by `kid`, `alg` and key type) and none of them verified the signature. Selection succeeded — otherwise you would see "Another algorithm expected, or no matching key(s) found" — so the keys you trust and the key that signed the token are different, or the token was modified. Spring Security reports the same condition through `NimbusJwtDecoder`, prefixed with "An error occurred while attempting to decode the Jwt:".
Why it happens
Same kid, different key
commonKey IDs like `default`, `rsa1` or a date are reused when a key is regenerated (per environment, per deployment, after losing the old key). The verifier finds a key with the right `kid` that never signed the token.
The resource server trusts another issuer's keys
commonA `jwk-set-uri` pointing at a different realm, tenant or environment than the one issuing the tokens.
HMAC secret differs between services
occasionalWith HS256 and a `MACVerifier`, any difference in the shared secret bytes (encoding, trailing newline) makes every signature invalid.
The token was changed after signing
occasionalHeader or payload re-encoded by a proxy, or a token assembled from parts of different tokens.
How to fix it
- 1.
Configure the issuer, not a hand-copied key set
`issuer-uri` makes Spring Security read `jwks_uri` from the issuer's discovery document and validate `iss` as well.
yaml # Spring Boot resource server: derive the JWK Set from the issuer's discovery document spring: security: oauth2: resourceserver: jwt: issuer-uri: https://issuer.example.com/realms/main - 2.
Compare thumbprints, not only kids
RFC 7638 thumbprints identify the actual key material. If the thumbprint of the published key differs from the one the issuer signs with, the `kid` is being reused.
java SignedJWT jwt = SignedJWT.parse(token); System.out.println(jwt.getHeader().getKeyID() + " " + jwt.getHeader().getAlgorithm()); JWKSet set = JWKSet.load(new java.net.URI("https://issuer.example.com/.well-known/jwks.json").toURL()); for (JWK key : set.getKeys()) { System.out.println(key.getKeyID() + " " + key.getAlgorithm() + " thumbprint=" + key.computeThumbprint()); }