Skip to content

[Duplicate Code] Token cache-update and refresh-scheduling block duplicated in all four OIDC providers #3875

@github-actions

Description

@github-actions

Duplicate Code Opportunity

Summary

  • Pattern: The "store token + compute refresh delay + schedule next refresh" block is copy-pasted verbatim into every OIDC token provider subclass
  • Locations: anthropic-oidc-token-provider.js lines 90–101, gcp-oidc-token-provider.js lines 161–172, oidc-token-provider.js (Azure) lines 144–155, aws-oidc-token-provider.js lines 168–178
  • Impact: 9–11 lines × 4 copies = ~40 duplicate lines; the REFRESH_FACTOR / MIN_REFRESH_MARGIN_SECS math appears four times — a single arithmetic fix or tuning change must be applied to every provider separately

Evidence

The following block (modulo variable name for the cached value) is identical across all four providers:

anthropic-oidc-token-provider.js lines 90–101:

const now = Math.floor(Date.now() / 1000);
this._cachedToken = access_token;
this._expiresAt = now + expires_in;

const refreshInSecs = Math.max(
  0,
  Math.min(
    expires_in * REFRESH_FACTOR,
    expires_in - MIN_REFRESH_MARGIN_SECS
  )
);
this._scheduleRefresh(Math.floor(refreshInSecs * 1000));

gcp-oidc-token-provider.js lines 161–172: identical (variable named accessToken / expiresIn).

oidc-token-provider.js (Azure) lines 144–155: identical.

aws-oidc-token-provider.js lines 168–178: identical except cached field is this._cachedCredentials.

BaseOidcTokenProvider already owns _expiresAt, REFRESH_FACTOR, and _scheduleRefresh(), making this an obvious base-class responsibility.

Suggested Refactoring

Add a protected helper to oidc-token-provider-base.js:

/**
 * Stores the new cached value, records expiry, and schedules the next refresh.
 * `@param` {unknown} value - token string or credentials object to cache
 * `@param` {number} expiresIn - token lifetime in seconds
 */
_storeAndScheduleRefresh(value, expiresIn) {
  const now = Math.floor(Date.now() / 1000);
  this._storeCachedValue(value);   // new abstract hook, or inline per subclass
  this._expiresAt = now + expiresIn;

  const refreshInSecs = Math.max(
    0,
    Math.min(
      expiresIn * REFRESH_FACTOR,
      expiresIn - MIN_REFRESH_MARGIN_SECS
    )
  );
  this._scheduleRefresh(Math.floor(refreshInSecs * 1000));
}

Because each subclass stores the value in a differently named field (_cachedToken vs _cachedCredentials), the simplest approach is to pass an assignment callback, or simply move the field assignment into an abstract _storeCachedValue(value) that each subclass implements. The _expiresAt update and the scheduling math move entirely to the base class.

Affected Files

  • containers/api-proxy/oidc-token-provider-base.js — add _storeAndScheduleRefresh() helper
  • containers/api-proxy/anthropic-oidc-token-provider.js — lines 90–101, replace with helper call
  • containers/api-proxy/gcp-oidc-token-provider.js — lines 161–172, replace with helper call
  • containers/api-proxy/oidc-token-provider.js — lines 144–155, replace with helper call
  • containers/api-proxy/aws-oidc-token-provider.js — lines 168–178, replace with helper call

Effort Estimate

Low–Medium


Detected by Duplicate Code Detector workflow. Run date: 2026-05-26

Generated by Duplicate Code Detector · sonnet46 2.8M ·

  • expires on Jun 25, 2026, 10:15 PM UTC

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions