{"record":{"id":"7e4bc8fa8737590c","repo":"apereo/cas","slug":"proof-jwt-algorithm-does-not-match-rsa-holder-key","errorCode":null,"errorMessage":"Proof JWT algorithm does not match RSA holder key","messagePattern":"Proof JWT algorithm does not match RSA holder key","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oidc-vc/src/main/java/org/apereo/cas/oidc/vc/issuer/proof/OidcVerifiableCredentialJwtProofValidator.java","lineNumber":91,"sourceCode":"            throw new IllegalArgumentException(\"Proof JWT signature validation failed\");\n        }\n    }\n\n    protected void verifyAudience(final SignedJWT signedJwt) throws ParseException {\n        val audiences = signedJwt.getJWTClaimsSet().getAudience();\n        val credentialIssuer = casProperties.getAuthn().getOidc().getCore().getIssuer();\n        if (audiences == null || !audiences.contains(credentialIssuer)) {\n            throw new IllegalArgumentException(\"Proof audience does not match credential issuer\");\n        }\n    }\n\n    protected void verifyAlgorithm(final SignedJWT signedJwt, final JWK holderJwk) {\n        val alg = signedJwt.getHeader().getAlgorithm();\n        if (alg == null || Algorithm.NONE.equals(alg)) {\n            throw new IllegalArgumentException(\"Proof JWT algorithm is invalid\");\n        }\n        if (holderJwk instanceof RSAKey && !JWSAlgorithm.Family.RSA.contains(alg)) {\n            throw new IllegalArgumentException(\"Proof JWT algorithm does not match RSA holder key\");\n        }\n        if (holderJwk instanceof ECKey && !JWSAlgorithm.Family.EC.contains(alg)) {\n            throw new IllegalArgumentException(\"Proof JWT algorithm does not match EC holder key\");\n        }\n    }\n\n    protected void verifyFreshness(final SignedJWT signedJwt) throws ParseException {\n        val claims = signedJwt.getJWTClaimsSet();\n        val issuedAt = claims.getIssueTime();\n        if (issuedAt == null) {\n            throw new IllegalArgumentException(\"Proof JWT is missing iat\");\n        }\n        val now = Instant.now(Clock.systemUTC());\n        val iat = issuedAt.toInstant();\n        if (iat.isAfter(now.plusSeconds(SECONDS_IN_FUTURE))) {\n            throw new IllegalArgumentException(\"Proof iat is in the future\");\n        }\n        if (iat.isBefore(now.minus(Duration.ofMinutes(MINUTES_IN_PAST)))) {","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-vc/src/main/java/org/apereo/cas/oidc/vc/issuer/proof/OidcVerifiableCredentialJwtProofValidator.java#L73-L109","documentation":"Thrown by OidcVerifiableCredentialJwtProofValidator.verifyAlgorithm when the holder JWK is an RSAKey but the proof JWT's alg header is not in the JWSAlgorithm.RSA family (e.g. an ES256-signed JWT presented against an RSA holder key). The algorithm must be cryptographically consistent with the presented holder key type.","triggerScenarios":"Proof JWT signed with an EC algorithm while the bound holder JWK is RSA; kid resolving to an RSA JWK but the client signing with an EC key; generic proof-builder hardcoding ES256 regardless of key type.","commonSituations":"Copy-pasted proof code using ES256 defaults while the key material bound to the credential request is RSA; key rotation replacing an EC key with RSA (or vice versa) without updating signing code.","solutions":["Sign the proof with an RSA-family algorithm (RS256/RS384/RS512, PS*) when the holder key is RSA.","Align the signing key with the holder JWK type bound to the request.","Make the proof builder choose the algorithm from the key type instead of hardcoding it."],"exampleFix":"// before\nsigned.sign(new ECDSASigner(ecKeyPair.getPrivate())); // EC alg, RSA holder key\n// after\nsigned.sign(new RSASSASigner(rsaKeyPair.getPrivate()));","handlingStrategy":"validation","validationCode":"if (holderJwk instanceof RSAKey && !JWSAlgorithm.Family.RSA.contains(alg)) {\n    throw new IllegalArgumentException(\"Use an RSA-family algorithm for RSA holder keys\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Derive the signing algorithm from the holder key type instead of hardcoding it.","Keep key type and algorithm in sync during key rotation."],"tags":["jwt","algorithm","rsa","key-mismatch","verifiable-credentials"],"backgroundTag":"invalid-argument-value","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}