{"record":{"id":"2ab43f766add5e70","repo":"apereo/cas","slug":"jwk-type-is-not-supported","errorCode":null,"errorMessage":"JWK type is not supported","messagePattern":"JWK type is not supported","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oidc-vc/src/main/java/org/apereo/cas/vc/presentation/OidcVerifiableCredentialPresentationResponseEndpointController.java","lineNumber":416,"sourceCode":"    private static JWK parsePublicJwk(final Map<?, ?> value) throws Exception {\n        val jwkValues = new LinkedHashMap<String, Object>();\n        value.forEach((key, entryValue) -> {\n            require(key instanceof String, \"JWK member name is invalid\");\n            jwkValues.put((String) key, entryValue);\n        });\n        val jwk = JWK.parse(jwkValues);\n        require(!jwk.isPrivate(), \"Holder JWK must not contain private key material\");\n        require(jwk instanceof ECKey || jwk instanceof RSAKey || jwk instanceof OctetKeyPair,\n            \"Holder JWK type is not supported\");\n        return jwk.toPublicJWK();\n    }\n\n    private static boolean verify(final SignedJWT signedJwt, final JWK jwk) throws Exception {\n        val verifier = switch (jwk) {\n            case final ECKey ecKey -> new ECDSAVerifier(ecKey.toPublicJWK());\n            case final RSAKey rsaKey -> new RSASSAVerifier(rsaKey.toPublicJWK());\n            case final OctetKeyPair octetKeyPair -> new Ed25519Verifier(octetKeyPair.toPublicJWK());\n            default -> throw new IllegalArgumentException(\"JWK type is not supported\");\n        };\n        return signedJwt.verify((JWSVerifier) verifier);\n    }\n\n    private static void validateTimeClaims(final Map<String, Object> claims,\n                                           final boolean issuedAtRequired,\n                                           @Nullable final Instant earliestIssuedAt) {\n        val now = Instant.now(Clock.systemUTC());\n        val expirationTime = readNumericDate(claims, \"exp\", false);\n        require(expirationTime == null || now.minus(CLOCK_SKEW).isBefore(expirationTime), \"JWT has expired\");\n        val notBefore = readNumericDate(claims, \"nbf\", false);\n        require(notBefore == null || !now.plus(CLOCK_SKEW).isBefore(notBefore), \"JWT is not yet valid\");\n        val issuedAt = readNumericDate(claims, \"iat\", issuedAtRequired);\n        require(issuedAt == null || !now.plus(CLOCK_SKEW).isBefore(issuedAt), \"JWT issue time is in the future\");\n        require(earliestIssuedAt == null || (issuedAt != null\n                && !issuedAt.isBefore(earliestIssuedAt.minus(CLOCK_SKEW))),\n            \"Key binding JWT predates the presentation transaction\");\n    }","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-vc/src/main/java/org/apereo/cas/vc/presentation/OidcVerifiableCredentialPresentationResponseEndpointController.java#L398-L434","documentation":"OidcVerifiableCredentialPresentationResponseEndpointController.verify selects a Nimbus JWS verifier based on the JWK's key type (EC, RSA, or OKP/Ed25519) and throws IllegalArgumentException for any other key type, since the switch has no verifier for e.g. octet-sequence (symmetric) keys.","triggerScenarios":"Verifying a signed JWT (verifyCredentialSignature or validateKeyBindingJwt) with a JWK whose 'kty' is not EC, RSA, or OKP — e.g. a symmetric 'oct' key, an unrecognized key type, or malformed key data producing a default JWK.","commonSituations":"Presentation request signed with an HMAC/symmetric key instead of an asymmetric one; JWKS published with unsupported key types; server JWK parser returning OctetSequenceKey for an unexpected key.","solutions":["Re-sign the JWT with an EC, RSA, or Ed25519 (OKP) key","Check the key's 'kty' in the source JWKS and publish/use only supported key types","Extend the switch in verify() if a new key type must be supported"],"exampleFix":"// before\nJWSSigner signer = new MACSigner(secret); // symmetric oct key\nsignedJwt.sign(signer);\n// after\nJWSSigner signer = new ECDSASigner((ECKey) ecJwk); // EC key supported by verify()\nsignedJwt.sign(signer);","handlingStrategy":"validation","validationCode":"Set<String> supported = Set.of(\"EC\",\"RSA\",\"OKP\");\nif (!supported.contains(jwk.getKeyType().getValue())) throw new IllegalArgumentException(\"unsupported kty\");","typeGuard":"boolean verifiable(JWK jwk) { return jwk instanceof ECKey || jwk instanceof RSAKey || jwk instanceof OctetKeyPair; }","tryCatchPattern":"try { return verify(signedJwt, jwk); }\ncatch (IllegalArgumentException e) { logger.warn(\"Unsupported JWK kty={}\", jwk.getKeyType()); return false; }","preventionTips":["Publish only EC/RSA/OKP keys in JWKS","Filter key candidates by kty before calling verify","Use asymmetric keys, never symmetric 'oct' keys, for VC signatures"],"tags":["jwk","jwt","signature","unsupported"],"backgroundTag":"unsupported-operation","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"}