quarkusio/quarkus · error · SpiffeConnectionException

JWT-SVID 'aud' claim is not a string or array of strings

Error message

JWT-SVID 'aud' claim is not a string or array of strings

What it means

The 'aud' claim must be either a single string or an array of strings. Any other JSON type (number, object, boolean, null handled separately) makes the token unparseable as a valid audience set, so SpiffeConnectionException is thrown.

Source

Thrown at extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeClientImpl.java:253

        Object aud = payload.getValue("aud");
        if (aud == null) {
            throw new SpiffeConnectionException("JWT-SVID from SPIRE agent is missing the required 'aud' claim");
        }
        final Set<String> audience;
        if (aud instanceof JsonArray audienceAsArray) {
            audience = new HashSet<>(audienceAsArray.size());
            for (int i = 0; i < audienceAsArray.size(); i++) {
                if (audienceAsArray.getValue(i) instanceof String audienceAsString) {
                    audience.add(audienceAsString);
                } else {
                    throw new SpiffeConnectionException(
                            "JWT-SVID 'aud' array element at index " + i + " is not a string:" + audienceAsArray.getValue(i));
                }
            }
        } else if (aud instanceof String audienceAsString) {
            audience = Set.of(audienceAsString);
        } else {
            throw new SpiffeConnectionException(
                    "JWT-SVID 'aud' claim is not a string or array of strings");
        }
        if (!audience.containsAll(requestedAudiences)) {
            throw new SpiffeConnectionException(
                    "JWT-SVID 'aud' claim does not contain the requested audiences; requested: "
                            + requestedAudiences + ", received: " + audience);
        }
        if (audience.size() != requestedAudiences.size()) {
            throw new SpiffeConnectionException(
                    "JWT-SVID 'aud' claim contains unexpected extra audiences; requested: "
                            + requestedAudiences + ", received: " + audience);
        }

        Long exp = payload.getLong("exp");
        if (exp == null) {
            throw new SpiffeConnectionException("JWT-SVID from SPIRE agent is missing the required 'exp' claim");
        }
        Instant expiry = Instant.ofEpochSecond(exp);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Fix the token producer so aud is a string or array of strings
  2. Use real SPIRE-issued JWT-SVIDs instead of synthetic ones
  3. Validate token payloads with a JWT linter before injecting them into tests

Example fix

// before
{"aud": 12345}
// after
{"aud": "https://api.example.com"}
Defensive patterns

Strategy: type-guard

Type guard

static boolean audTypeOk(Object aud) {
    return aud instanceof String || aud instanceof JsonArray;
}

Try / catch

try {
    return spiffeClient.getWorkloadJsonWebToken(audiences).await().indefinitely();
} catch (SpiffeConnectionException e) {
    if (e.getMessage().contains("not a string or array of strings")) {
        // fix token serialization
    }
    throw e;
}

Prevention

When it happens

Trigger: Payload contains aud as a non-string, non-array JSON value, e.g. aud: 123 or aud: {"x":1} in a stubbed or corrupted token.

Common situations: Hand-crafted test tokens with wrong claim types; scripts that build JWT payloads programmatically with incorrect serialization.

Related errors


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