quarkusio/quarkus · error · SpiffeConnectionException

JWT-SVID from SPIRE agent is already expired

Error message

JWT-SVID from SPIRE agent is already expired

What it means

The Quarkus SPIFFE client fetches JWT-SVIDs from a SPIRE Workload API agent. After parsing the token payload, it checks the 'exp' claim and rejects any token whose expiry is already in the past. This prevents callers from using a token that cannot possibly be valid for authentication.

Source

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

        }
        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);
        if (expiry.isBefore(Instant.now())) {
            throw new SpiffeConnectionException("JWT-SVID from SPIRE agent is already expired");
        }

        record WorkloadJsonWebTokenImpl(String token, String subject, Set<String> audience,
                Instant expiry) implements WorkloadJsonWebToken {
        }
        return new WorkloadJsonWebTokenImpl(token, sub, Set.copyOf(audience), expiry);
    }

    private static WorkloadCertificateDocument toWorkloadCertificate(X509SVIDResponse response)
            throws SpiffeConnectionException {
        List<X509SVID> svids = response.getSvidsList();
        if (svids.isEmpty()) {
            throw new SpiffeConnectionException("X.509-SVID response from SPIRE agent contains no SVIDs");
        }
        X509SVID svid = svids.get(0);

        String protoSpiffeId = svid.getSpiffeId();
        SpiffeValidator.validateSpiffeId(protoSpiffeId);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Synchronize clocks between the application and the SPIRE agent/server (NTP, kubelet clock settings).
  2. Increase the JWT-SVID TTL in the SPIRE server entry (ttl_seconds) or re-request tokens just before use instead of caching them.
  3. Retry the fetch; a fresh token should have a future exp if clocks agree.
  4. Check the SPIRE agent logs/health for stale or cached SVIDs and restart the agent if it serves expired tokens.

Example fix

// before: token fetched once at startup and reused
WorkloadJsonWebToken jwt = client.fetchWorkloadJsonWebTokens(...);
// after: re-fetch when close to expiry
WorkloadJsonWebToken jwt = expiry.isBefore(Instant.now().plusSeconds(60))
        ? client.fetchWorkloadJsonWebTokens(...)
        : cached;
Defensive patterns

Strategy: retry

Validate before calling

byte[] token = fetchTokenRaw();
long exp = parseClaim(token, "exp");
if (Instant.ofEpochSecond(exp).isBefore(Instant.now().plusSeconds(30))) {
    // refresh before use
}

Try / catch

try {
    jwt = client.fetchWorkloadJsonWebTokens(aud);
} catch (SpiffeConnectionException e) {
    if (e.getMessage().contains("already expired")) {
        jwt = retryWithBackoff(() -> client.fetchWorkloadJsonWebTokens(aud));
    } else throw e;
}

Prevention

When it happens

Trigger: Calling fetchWorkloadJsonWebTokens (via WorkloadApiClient) when the SPIRE agent returns a JWT-SVID whose parsed 'exp' claim epoch-second value is before Instant.now().

Common situations: SPIRE agent clock skew with the application container; a SPIRE server issuing short-lived SVIDs (e.g. 5 min TTL) that expired between signing and delivery; NTP drift in Kubernetes pods; agent returning cached/stale tokens.

Related errors


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