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
- 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
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
- 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
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
- Proof JWT signature validation failed
- Unable to accept the ID token with an invalid [sub] claim
- Unknown authorization header type
- Token has expired: and is after
- Token cannot be used before
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)