apereo/cas · error · IllegalArgumentException

JWK type is not supported

Error message

JWK type is not supported

What it means

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.

Solutions

  1. Re-sign the JWT with an EC, RSA, or Ed25519 (OKP) key
  2. Check the key's 'kty' in the source JWKS and publish/use only supported key types
  3. Extend the switch in verify() if a new key type must be supported

Example fix

// before
JWSSigner signer = new MACSigner(secret); // symmetric oct key
signedJwt.sign(signer);
// after
JWSSigner signer = new ECDSASigner((ECKey) ecJwk); // EC key supported by verify()
signedJwt.sign(signer);
Defensive patterns

Strategy: validation

Validate before calling

Set<String> supported = Set.of("EC","RSA","OKP");
if (!supported.contains(jwk.getKeyType().getValue())) throw new IllegalArgumentException("unsupported kty");

Type guard

boolean verifiable(JWK jwk) { return jwk instanceof ECKey || jwk instanceof RSAKey || jwk instanceof OctetKeyPair; }

Try / catch

try { return verify(signedJwt, jwk); }
catch (IllegalArgumentException e) { logger.warn("Unsupported JWK kty={}", jwk.getKeyType()); return false; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/2ab43f766add5e70. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-oidc-vc/src/main/java/org/apereo/cas/vc/presentation/OidcVerifiableCredentialPresentationResponseEndpointController.java:416

    private static JWK parsePublicJwk(final Map<?, ?> value) throws Exception {
        val jwkValues = new LinkedHashMap<String, Object>();
        value.forEach((key, entryValue) -> {
            require(key instanceof String, "JWK member name is invalid");
            jwkValues.put((String) key, entryValue);
        });
        val jwk = JWK.parse(jwkValues);
        require(!jwk.isPrivate(), "Holder JWK must not contain private key material");
        require(jwk instanceof ECKey || jwk instanceof RSAKey || jwk instanceof OctetKeyPair,
            "Holder JWK type is not supported");
        return jwk.toPublicJWK();
    }

    private static boolean verify(final SignedJWT signedJwt, final JWK jwk) throws Exception {
        val verifier = switch (jwk) {
            case final ECKey ecKey -> new ECDSAVerifier(ecKey.toPublicJWK());
            case final RSAKey rsaKey -> new RSASSAVerifier(rsaKey.toPublicJWK());
            case final OctetKeyPair octetKeyPair -> new Ed25519Verifier(octetKeyPair.toPublicJWK());
            default -> throw new IllegalArgumentException("JWK type is not supported");
        };
        return signedJwt.verify((JWSVerifier) verifier);
    }

    private static void validateTimeClaims(final Map<String, Object> claims,
                                           final boolean issuedAtRequired,
                                           @Nullable final Instant earliestIssuedAt) {
        val now = Instant.now(Clock.systemUTC());
        val expirationTime = readNumericDate(claims, "exp", false);
        require(expirationTime == null || now.minus(CLOCK_SKEW).isBefore(expirationTime), "JWT has expired");
        val notBefore = readNumericDate(claims, "nbf", false);
        require(notBefore == null || !now.plus(CLOCK_SKEW).isBefore(notBefore), "JWT is not yet valid");
        val issuedAt = readNumericDate(claims, "iat", issuedAtRequired);
        require(issuedAt == null || !now.plus(CLOCK_SKEW).isBefore(issuedAt), "JWT issue time is in the future");
        require(earliestIssuedAt == null || (issuedAt != null
                && !issuedAt.isBefore(earliestIssuedAt.minus(CLOCK_SKEW))),
            "Key binding JWT predates the presentation transaction");
    }

View on GitHub (pinned to e7288fc434)