{"record":{"id":"ef1d7027cbc52424","repo":"apereo/cas","slug":"proof-jwt-algorithm-is-invalid","errorCode":null,"errorMessage":"Proof JWT algorithm is invalid","messagePattern":"Proof JWT algorithm is invalid","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":88,"sourceCode":"            verifier = new ECDSAVerifier(ecKey);\n        }\n        if (verifier == null || !signedJwt.verify(verifier)) {\n            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))) {","sourceCodeStart":70,"sourceCodeEnd":106,"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#L70-L106","documentation":"Thrown by OidcVerifiableCredentialJwtProofValidator.verifyAlgorithm when the proof JWT's alg header is null or equals 'none'. Key-bound proofs must be signed; unsigned JWTs are rejected outright to prevent trivially forged key-possession proofs.","triggerScenarios":"Building the proof JWT with Algorithm.NONE or leaving the algorithm unset; constructing a SignedJWT without calling sign() with a real JWSAlgorithm; misconfigured JWT library defaulting to unsecured mode.","commonSituations":"Developers test with unsigned JWTs to inspect claims first and forget to sign; JWT-building helper libraries emitting 'none' when no signer is supplied; disabled signing in a shared proof-builder utility.","solutions":["Sign the proof JWT with a concrete JWSAlgorithm (e.g. RS256 or ES256) matching the holder key.","Remove any code path that builds the proof with Algorithm.NONE.","Ensure the JWT builder/signer is configured with a real signer before sending the credential request."],"exampleFix":"// before\nJWSHeader header = new JWSHeader(JWSAlgorithm.NONE);\n// after\nJWSHeader header = new JWSHeader(JWSAlgorithm.RS256);","handlingStrategy":"validation","validationCode":"JWSAlgorithm alg = signedJwt.getHeader().getAlgorithm();\nif (alg == null || Algorithm.NONE.equals(alg)) {\n    throw new IllegalArgumentException(\"Proof must be signed\");\n}","typeGuard":"boolean isSignedProof(SignedJWT jwt) { return jwt.getHeader().getAlgorithm() != null && !Algorithm.NONE.equals(jwt.getHeader().getAlgorithm()); }","tryCatchPattern":null,"preventionTips":["Always supply a real signer when constructing the proof JWT.","Add a local assertion that alg is not 'none' before sending."],"tags":["jwt","algorithm","unsigned-jwt","oidc","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"}