jwtk/jjwt · error · UnsupportedKeyException

JWK Set keys[${i}]: ${e.getMessage()}

Error message

JWK Set keys[${i}]: ${e.getMessage()}

What it means

When parsing a JWK Set, each candidate key entry is converted with JWK_CONVERTER.applyFrom. If conversion raises UnsupportedKeyException (an unsupported key type/algorithm) and ignoreUnsupported is false, this error wraps the original message with the entry index, e.g. "JWK Set keys[2]: ...". It lets callers know exactly which key in the set was unsupported.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/JwkSetConverter.java:127

            if (!(key instanceof String)) {
                String msg = "JWK Set map keys must be Strings. Encountered key '" + key + "' of type " +
                        key.getClass().getName();
                throw new IllegalArgumentException(msg);
            }
            String skey = (String) key;
            src.put(skey, entry.getValue());
        }

        Set<Jwk<?>> jwks = new LinkedHashSet<>(size);
        int i = 0; // keep track of which element fails (if any)
        for (Object candidate : ((Collection<?>) val)) {
            try {
                Jwk<?> jwk = JWK_CONVERTER.applyFrom(candidate);
                jwks.add(jwk);
            } catch (UnsupportedKeyException e) {
                if (!ignoreUnsupported) {
                    String msg = "JWK Set keys[" + i + "]: " + e.getMessage();
                    throw new UnsupportedKeyException(msg, e);
                }
            } catch (IllegalArgumentException | KeyException e) {
                if (!ignoreUnsupported) {
                    String msg = "JWK Set keys[" + i + "]: " + e.getMessage();
                    throw new MalformedKeySetException(msg, e);
                }
            }
            i++;
        }

        // Replace the `keys` value with validated entries:
        src.remove(PARAM.getId());
        src.put(PARAM.getId(), jwks);
        return new DefaultJwkSet(PARAM, src);
    }
}

View on GitHub (pinned to fb71496164)

Solutions

  1. Upgrade jjwt to the latest version so more key types/algorithms are supported.
  2. Parse with ignoreUnsupported=true (e.g. via JwkSet parsing options) to skip unsupported keys instead of failing.
  3. Filter the JWKS response to only supported "kty" values before conversion.
  4. Check the wrapped message for keys[N] index to inspect and remove/replace the offending entry.

Example fix

// before
JwkSet jwks = Jwks.set().add(rawMap).build(); // strict: throws on unsupported kty

// after
JwkSet jwks = Jwks.set().add(rawMap).ignoreUnsupported(true).build(); // skips unsupported keys
Defensive patterns

Strategy: try-catch

Validate before calling

Set<String> supported = Set.of("EC", "RSA", "oct", "OKP");
boolean allSupported(List<Map<String, Object>> keys) {
    return keys.stream().allMatch(k -> supported.contains(k.get("kty")));
}

Try / catch

try {
    jwkSet = parse(json);
} catch (UnsupportedKeyException e) {
    // optionally re-parse with ignoreUnsupported(true) or upgrade jjwt
    logger.warn("Skipping unsupported JWK: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Parsing/converting a JWK Set whose keys array contains an entry with an unsupported "kty" or algorithm, with ignoreUnsupported=false (default strict mode).

Common situations: JWK Set published by an identity provider includes key types this jjwt version does not support (e.g. oct-pair, AKP, unusual EC curves, or keys requiring a newer jjwt release); strict parsing of an OP's JWKS endpoint that mixes supported and unsupported keys.

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 jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/4694d75bce61895c. Report an issue: GitHub.