{"record":{"id":"9e098e5ba58a5485","repo":"keycloak/keycloak","slug":"invalid-jws-signature","errorCode":null,"errorMessage":"Invalid jws signature","messagePattern":"Invalid jws signature","errorType":"exception","errorClass":"VerificationException","httpStatus":null,"severity":"critical","filePath":"core/src/main/java/org/keycloak/sdjwt/JwsToken.java","lineNumber":93,"sourceCode":"        }\n        return jws;\n    }\n\n    public void verifySignature(SignatureVerifierContext verifier) throws VerificationException {\n        Objects.requireNonNull(verifier, \"verifier must not be null\");\n        String headerAlgorithm = jwsHeader == null || jwsHeader.getAlgorithm() == null\n                ? null\n                : jwsHeader.getRawAlgorithm();\n        String verifierAlgorithm = verifier.getAlgorithm();\n        if (headerAlgorithm == null || verifierAlgorithm == null || !headerAlgorithm.equals(verifierAlgorithm)) {\n            throw new VerificationException(String.format(\n                    \"JWS header algorithm '%s' does not match verifier algorithm '%s'\",\n                    headerAlgorithm, verifierAlgorithm));\n        }\n        try {\n            if (!verifier.verify(jwsInput.getEncodedSignatureInput().getBytes(StandardCharsets.UTF_8),\n                                 jwsInput.getSignature())) {\n                throw new VerificationException(\"Invalid jws signature\");\n            }\n        } catch (Exception e) {\n            throw new VerificationException(e);\n        }\n    }\n\n    public Optional<String> getSdHashAlgorithm() {\n        return Optional.ofNullable(payload.get(OID4VCConstants.CLAIM_NAME_SD_HASH_ALGORITHM))\n                       .map(JsonNode::textValue);\n    }\n\n    public String getJws() {\n        return jws;\n    }\n\n    public void setJws(String jws) {\n        this.jws = jws;\n    }","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/keycloak/keycloak/blob/66c7e15a3788de7764f07dd2558275a02770e16d/core/src/main/java/org/keycloak/sdjwt/JwsToken.java#L75-L111","documentation":"Thrown by JwsToken.verifySignature() (line 93) when verifier.verify(encodedSignatureInput, signature) returns false: the signature does not validate against the signing input using the verifier's public key. The token was tampered with, signed by a different key, or corrupted. This is a security-critical rejection.","triggerScenarios":"The token's signature segment was modified; the verifier holds a stale or wrong issuer key; a token signed by one issuer is verified against another's key; the JWS string is truncated; for key binding, the holder signed with a key different from cnf.jwk.","commonSituations":"Wrong issuer JWKS configured; key rotation without JWKS refresh; man-in-the-middle tampering; copy-paste truncation of the JWS; holder key binding JWT signed by a different holder key than the cnf.jwk in the credential.","solutions":["Confirm the verifier uses the issuer's current public key (refresh the JWKS).","Check the JWS string is not truncated or altered by whitespace/encoding.","For key binding, ensure the holder key matches the cnf.jwk in the SD-JWT VC.","Verify the signing input is the UTF-8 bytes of the encoded signature input (header.payload)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// No meaningful pre-check: signature validity is the verifier's job. Ensure the right key first.\npublic static SignatureVerifierContext loadCurrentIssuerVerifier(JwkParsingSource source) {\n    // refresh JWKS so the key is current, then build the verifier\n    return source.refreshAndBuild();\n}","typeGuard":null,"tryCatchPattern":"// Signature failure is security-critical; never retry with relaxed checks.\ntry {\n    token.verifySignature(verifier);\n} catch (VerificationException e) {\n    // treat as invalid credential — do not fall back to a different key to 'make it pass'\n    throw e;\n}","preventionTips":["Keep the issuer/holder public key current; refresh JWKS on rotation.","Do not truncate or alter the JWS string (watch copy-paste and encoding).","For key binding, verify the holder key matches cnf.jwk exactly.","Never fall back to alternate keys on signature failure — reject the token."],"tags":["sd-jwt","jws","verification","signature","security"],"backgroundTag":null,"analyzedSha":"66c7e15a3788de7764f07dd2558275a02770e16d","analyzedAt":"2026-08-14T01:36:42.651Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}