quarkusio/quarkus · error · org.jose4j.jwt.MalformedClaimException

expected claim %s must be a list of strings

Error message

expected claim %s must be a list of strings

What it means

Thrown by OidcProvider's CustomClaimsValidator when a required claim configured in quarkus.oidc.token.required-claims is expected to be a single string value in the token, but the app configured MULTIPLE required values for that claim (a set), and the token claim is a plain string. A string claim can only be compared against exactly one expected value, so the configuration is contradictory and MalformedClaimException is thrown.

Source

Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProvider.java:746

                }
            }
            return null;
        }

        private static String validate(String requiredClaimName, Set<String> requiredClaimValues, JwtClaims claims)
                throws MalformedClaimException {
            if (!claims.hasClaim(requiredClaimName)) {
                return "claim " + requiredClaimName + " is missing";
            }
            if (claims.isClaimValueString(requiredClaimName)) {
                if (requiredClaimValues.size() == 1) {
                    String actualClaimValue = claims.getStringClaimValue(requiredClaimName);
                    String requiredClaimValue = requiredClaimValues.iterator().next();
                    if (!requiredClaimValue.equals(actualClaimValue)) {
                        return "claim " + requiredClaimName + " does not match expected value of " + requiredClaimValues;
                    }
                } else {
                    throw new MalformedClaimException("expected claim " + requiredClaimName + " must be a list of strings");
                }
            } else {
                if (claims.isClaimValueStringList(requiredClaimName)) {
                    List<String> actualClaimValues = claims.getStringListClaimValue(requiredClaimName);
                    for (String requiredClaimValue : requiredClaimValues) {
                        if (!actualClaimValues.contains(requiredClaimValue)) {
                            return "claim " + requiredClaimName + " does not match expected value of " + requiredClaimValues;
                        }
                    }
                } else {
                    throw new MalformedClaimException(
                            "expected claim " + requiredClaimName + " must be a list of strings or a string");
                }
            }
            return null;
        }
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Configure only ONE required value per claim if the token emits it as a plain string
  2. If multiple alternatives are needed, the token claim must be a JSON array of strings — ask the issuer to emit e.g. "acr": ["loa2","loa3"]
  3. Match exactly the value the token actually carries (decode the token to inspect the claim type)
  4. Use a custom Validator bean instead of static config if flexible matching is required

Example fix

# before (token acr is a plain string "loa2")
quarkus.oidc.token.required-claims.acr=loa2,loa3
# after
quarkus.oidc.token.required-claims.acr=loa2
Defensive patterns

Strategy: validation

Validate before calling

// decode the token and check the claim type before configuring multiple expected values
var claims = decodeJwtClaims(token);
Object acr = claims.get("acr");
if (!(acr instanceof List)) {
    // claim is a plain string: configure exactly ONE required value
}

Type guard

boolean isStringOrStringList(Object v) {
    return v instanceof String || (v instanceof List<?> l && l.stream().allMatch(String.class::isInstance));
}

Prevention

When it happens

Trigger: quarkus.oidc.token.required-claims.<name> maps to a set with 2+ values (e.g. comma-separated list) while the verified token's claim with that name is a single string, not a JSON array of strings.

Common situations: Developers write required-claims.acr=loa2,loa3 expecting OR-matching, but the provider emits acr as the string 'loa2' rather than an array; misunderstanding that multiple values only work when the token claim is a string list.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/2395ef5fb5461d98. Report an issue: GitHub.