quarkusio/quarkus · error · SpiffeConnectionException

JWT-SVID from SPIRE agent is missing the required 'aud' clai

Error message

JWT-SVID from SPIRE agent is missing the required 'aud' claim

What it means

Every JWT-SVID must carry an 'aud' claim identifying the intended audiences. If the decoded payload has no 'aud' claim at all, the client cannot verify the requested audiences and throws SpiffeConnectionException.

Source

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

        if (token.isBlank()) {
            throw new SpiffeConnectionException("JWT-SVID from SPIRE agent has no token");
        }
        String[] parts = token.split("\\.");
        if (parts.length != 3) {
            throw new SpiffeConnectionException("JWT-SVID from SPIRE agent is not a valid JWS Compact Serialization");
        }
        JsonObject payload = new JsonObject(new String(Base64.getUrlDecoder().decode(parts[1])));

        String sub = payload.getString("sub");
        SpiffeValidator.validateSpiffeId(sub);
        if (!sub.equals(svid.getSpiffeId())) {
            throw new SpiffeConnectionException(
                    "JWT-SVID proto SPIFFE ID does not match the 'sub' claim; proto: " + svid.getSpiffeId() + ", sub: " + sub);
        }

        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");
        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Verify with spire-agent api fetch jwt -audience <aud> that the agent issues tokens containing aud
  2. Upgrade or reconfigure the SPIRE agent so JWT-SVIDs include the aud claim
  3. Fix any test fixtures/stubs to include an aud claim in the fabricated token

Example fix

// before (test stub payload)
{"sub":"spiffe://example.org/workload","exp":1735689600}
// after
{"sub":"spiffe://example.org/workload","aud":["https://api.example.com"],"exp":1735689600}
Defensive patterns

Strategy: type-guard

Type guard

static boolean hasAudClaim(String jwt) {
    String[] p = jwt.split("\\.");
    if (p.length != 3) return false;
    JsonObject payload = new JsonObject(new String(Base64.getUrlDecoder().decode(p[1])));
    return payload.containsKey("aud");
}

Try / catch

try {
    return spiffeClient.getWorkloadJsonWebToken(audiences).await().indefinitely();
} catch (SpiffeConnectionException e) {
    if (e.getMessage().contains("missing the required 'aud'")) {
        // verify SPIRE agent issues aud-bearing tokens
    }
    throw e;
}

Prevention

When it happens

Trigger: SPIRE agent returned a JWT whose payload lacks 'aud' entirely — usually an agent-side issuance problem or a non-SPIRE token substituted for a real JWT-SVID.

Common situations: Older/misconfigured SPIRE agent issuing tokens without audience; test stubs returning hand-crafted JWTs missing claims; token actually being an access-token variant without aud.

Related errors


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