{"record":{"id":"314203c1575fc6a4","repo":"quarkusio/quarkus","slug":"jwt-svid-from-spire-agent-is-missing-the-required","errorCode":null,"errorMessage":"JWT-SVID from SPIRE agent is missing the required 'aud' claim","messagePattern":"JWT-SVID from SPIRE agent is missing the required 'aud' claim","errorType":"exception","errorClass":"SpiffeConnectionException","httpStatus":null,"severity":"error","filePath":"extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeClientImpl.java","lineNumber":237,"sourceCode":"        if (token.isBlank()) {\n            throw new SpiffeConnectionException(\"JWT-SVID from SPIRE agent has no token\");\n        }\n        String[] parts = token.split(\"\\\\.\");\n        if (parts.length != 3) {\n            throw new SpiffeConnectionException(\"JWT-SVID from SPIRE agent is not a valid JWS Compact Serialization\");\n        }\n        JsonObject payload = new JsonObject(new String(Base64.getUrlDecoder().decode(parts[1])));\n\n        String sub = payload.getString(\"sub\");\n        SpiffeValidator.validateSpiffeId(sub);\n        if (!sub.equals(svid.getSpiffeId())) {\n            throw new SpiffeConnectionException(\n                    \"JWT-SVID proto SPIFFE ID does not match the 'sub' claim; proto: \" + svid.getSpiffeId() + \", sub: \" + sub);\n        }\n\n        Object aud = payload.getValue(\"aud\");\n        if (aud == null) {\n            throw new SpiffeConnectionException(\"JWT-SVID from SPIRE agent is missing the required 'aud' claim\");\n        }\n        final Set<String> audience;\n        if (aud instanceof JsonArray audienceAsArray) {\n            audience = new HashSet<>(audienceAsArray.size());\n            for (int i = 0; i < audienceAsArray.size(); i++) {\n                if (audienceAsArray.getValue(i) instanceof String audienceAsString) {\n                    audience.add(audienceAsString);\n                } else {\n                    throw new SpiffeConnectionException(\n                            \"JWT-SVID 'aud' array element at index \" + i + \" is not a string:\" + audienceAsArray.getValue(i));\n                }\n            }\n        } else if (aud instanceof String audienceAsString) {\n            audience = Set.of(audienceAsString);\n        } else {\n            throw new SpiffeConnectionException(\n                    \"JWT-SVID 'aud' claim is not a string or array of strings\");\n        }","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeClientImpl.java#L219-L255","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify with spire-agent api fetch jwt -audience <aud> that the agent issues tokens containing aud","Upgrade or reconfigure the SPIRE agent so JWT-SVIDs include the aud claim","Fix any test fixtures/stubs to include an aud claim in the fabricated token"],"exampleFix":"// before (test stub payload)\n{\"sub\":\"spiffe://example.org/workload\",\"exp\":1735689600}\n// after\n{\"sub\":\"spiffe://example.org/workload\",\"aud\":[\"https://api.example.com\"],\"exp\":1735689600}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"static boolean hasAudClaim(String jwt) {\n    String[] p = jwt.split(\"\\\\.\");\n    if (p.length != 3) return false;\n    JsonObject payload = new JsonObject(new String(Base64.getUrlDecoder().decode(p[1])));\n    return payload.containsKey(\"aud\");\n}","tryCatchPattern":"try {\n    return spiffeClient.getWorkloadJsonWebToken(audiences).await().indefinitely();\n} catch (SpiffeConnectionException e) {\n    if (e.getMessage().contains(\"missing the required 'aud'\")) {\n        // verify SPIRE agent issues aud-bearing tokens\n    }\n    throw e;\n}","preventionTips":["Use real SPIRE-issued SVIDs in tests, not hand-made JWTs","Verify with spire-agent api fetch jwt that tokens include aud","Keep agents upgraded so issued SVIDs meet the JWT-SVID standard"],"tags":["spiffe","jwt","missing-claim"],"backgroundTag":"jwt-missing-claim","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}