Interface JwksRefresher

All Superinterfaces:
AutoCloseable, Closeable, io.confluent.security.trustservice.store.TrustCacheJwksChangeListener

public interface JwksRefresher extends io.confluent.security.trustservice.store.TrustCacheJwksChangeListener, Closeable
Coordinates expedited JWKS refresh on broker-side kid cache misses.

An active refresher (DefaultJwksRefresher) maintains a small overlay cache of JsonWebKeySets populated by asynchronous calls to the regional JWKS Fetch Service (via JwksFetchServiceClient). When a verification path encounters an unknown kid it calls maybeExpediteRefresh(String, String, String, int) which (subject to cooldown and in-flight dedup) submits a fetch task to a small bounded thread pool. Callers then read getOverlay(String) to consult the overlay during key resolution.

The refresher subscribes to TrustCacheJwksChangeListener: on onJwksChanged it evicts the overlay entry and repopulates it from the live endpoint once the authoritative TrustCache rotates keys; on onJwksRemoved it only evicts, since the issuer is gone and must not be re-fetched. Either way stale reads are avoided.

Obtain an instance via create(JwksFetchServiceClient, Metrics, Map): when expedited refresh is disabled a no-op implementation is returned, so callers never have to branch on the feature flag.

  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final int
    Default per-JWKS keyset size cap, matching IDENTITY_PROVIDER_JWKS_DEFAULT_LIMIT in cc-rbac-services (cc-trust-service/.../IdentityProviderManagerImpl.java).
  • Method Summary

    Modifier and Type
    Method
    Description
    void
     
    create(JwksFetchServiceClient fetchClient, org.apache.kafka.common.metrics.Metrics metrics, Map<String,?> configs)
    Creates a refresher from broker config.
    org.jose4j.jwk.JsonWebKeySet
    getOverlay(String cacheKey)
    Returns the overlay-cached JsonWebKeySet for cacheKey, or null if absent or expired.
    void
    maybeExpediteRefresh(String kid, String jwksEndpoint, String cacheKey, int maxJwksKeys)
    Possibly trigger an asynchronous expedited fetch of jwksEndpoint.
    void
    registerChangeListener(io.confluent.security.trustservice.store.TrustCache cache)
    Registers this refresher as cache's TrustCacheJwksChangeListener, at most once over the refresher's lifetime.

    Methods inherited from interface io.confluent.security.trustservice.store.TrustCacheJwksChangeListener

    onJwksChanged, onJwksRemoved
  • Field Details

    • DEFAULT_MAX_JWKS_KEYS

      static final int DEFAULT_MAX_JWKS_KEYS
      Default per-JWKS keyset size cap, matching IDENTITY_PROVIDER_JWKS_DEFAULT_LIMIT in cc-rbac-services (cc-trust-service/.../IdentityProviderManagerImpl.java). Used as a floor when computing the per-call cap; the rbac-extractor may accept more keys for individual providers via the TRUST_SERVICE_SCHEDULER_JWKS_LIMIT_FF LaunchDarkly override, in which case the caller should pass max(cachedSet.size(), DEFAULT_MAX_JWKS_KEYS) so the overlay never trims below what TrustCache already holds.
      See Also:
  • Method Details

    • maybeExpediteRefresh

      void maybeExpediteRefresh(String kid, String jwksEndpoint, String cacheKey, int maxJwksKeys)
      Possibly trigger an asynchronous expedited fetch of jwksEndpoint. The call is non-blocking. Subsequent calls for the same cacheKey are dropped while a fetch is in-flight, and further calls are suppressed during the cooldown window after a completed fetch.
      Parameters:
      kid - the JWT key id that triggered the miss (used to detect KID_MISSING)
      jwksEndpoint - upstream JWKS URI to forward to the fetch service
      cacheKey - the V2 trust-cache key (issuer:jwksEndpoint)
      maxJwksKeys - maximum number of keys retained from the fetched keyset; entries beyond this index are dropped to match the upstream TrustCache cap
    • getOverlay

      org.jose4j.jwk.JsonWebKeySet getOverlay(String cacheKey)
      Returns the overlay-cached JsonWebKeySet for cacheKey, or null if absent or expired.
    • registerChangeListener

      void registerChangeListener(io.confluent.security.trustservice.store.TrustCache cache)
      Registers this refresher as cache's TrustCacheJwksChangeListener, at most once over the refresher's lifetime.

      The verification path constructs a new KafkaVerificationKeyResolver per authentication and resolves the shared singleton TrustCache lazily, so registering directly from that path would re-set the listener on every request — and AbstractAuthCache#setJwksChangeListener logs a warning on each overwrite, spamming the logs under load. Implementations must therefore be idempotent and safe under concurrent first-time calls (the active implementation guards with a single compare-and-set).

      A single broker process owns one TrustCache and one refresher singleton, so registering once is sufficient; the refresher does not track multiple caches.

    • close

      void close()
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
    • create

      static JwksRefresher create(JwksFetchServiceClient fetchClient, org.apache.kafka.common.metrics.Metrics metrics, Map<String,?> configs)
      Creates a refresher from broker config. When expedited refresh is disabled (ConfluentConfigs.OAUTH_JWKS_EXPEDITED_REFRESH_ENABLE) a NoOpJwksRefresher is returned and no resources (thread pool, caches, metrics) are allocated, so the active implementation never has to reason about the disabled case. The tunables (cooldowns, overlay TTL and max entries) are read here so DefaultJwksRefresher stays decoupled from the config system; their defaults live in ConfluentConfigs.
      Parameters:
      configs - the broker config map (already validated against the broker ConfigDef)