Duplicate Code Opportunity
Summary
- Pattern:
OidcTokenProvider (Azure OIDC) manually reimplements the same token lifecycle methods — initialize(), isReady(), shutdown(), _scheduleRefresh(), _sleep(), and all the associated state variables — that already exist in BaseOidcTokenProvider. The AWS and GCP providers already extend BaseOidcTokenProvider; the Azure provider was not migrated.
- Locations:
containers/api-proxy/oidc-token-provider.js (lines 42–270) vs containers/api-proxy/oidc-token-provider-base.js (entire file)
- Impact: ~60 lines of duplicated security-critical auth-lifecycle logic; any bug fix or behaviour change in
BaseOidcTokenProvider (e.g. retry logic, shutdown safety, refresh scheduling) must also be applied manually to OidcTokenProvider or it silently diverges.
Evidence
oidc-token-provider-base.js (BaseOidcTokenProvider) — already extracted:
class BaseOidcTokenProvider {
constructor(providerPrefix, config) {
this._retryDelayMs = config.retryDelayMs ?? REFRESH_RETRY_DELAY_MS;
this._maxInitRetries = config.maxInitRetries ?? MAX_INIT_RETRIES;
this._expiresAt = 0;
this._refreshTimer = null;
this._refreshInFlight = null;
this._initialized = false;
this._initError = null;
}
async initialize() { /* retry loop with _doRefresh() */ }
isReady() { return !!(this._getCachedValue() && this._expiresAt > now); }
shutdown() { clearTimeout(this._refreshTimer); this._refreshTimer = null; }
_scheduleRefresh(delayMs) { /* setTimeout + unref */ }
// Abstract: _doRefresh(), _getCachedValue(), _getInitSuccessLogContext(), ...
}
oidc-token-provider.js (OidcTokenProvider / Azure) — duplicate copy:
class OidcTokenProvider { // ← does NOT extend BaseOidcTokenProvider
constructor(config) {
// ... Azure-specific fields ...
this._expiresAt = 0; // ← duplicated state
this._refreshTimer = null; // ← duplicated state
this._refreshInFlight = null; // ← duplicated state
this._initialized = false; // ← duplicated state
this._initError = null; // ← duplicated state
}
async initialize() { /* ~30 lines — same retry loop */ } // ← duplicated
getToken() { /* checks _cachedToken / triggers refresh */ } // ← duplicated
isReady() { /* same logic */ } // ← duplicated
shutdown() { /* same logic */ } // ← duplicated
_scheduleRefresh(delayMs) { /* ~20 lines — same pattern */ } // ← duplicated
_sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // ← duplicated
}
Meanwhile AwsOidcTokenProvider and GcpOidcTokenProvider do extend BaseOidcTokenProvider:
class AwsOidcTokenProvider extends BaseOidcTokenProvider { ... } // containers/api-proxy/aws-oidc-token-provider.js:48
class GcpOidcTokenProvider extends BaseOidcTokenProvider { ... } // containers/api-proxy/gcp-oidc-token-provider.js:10
Suggested Refactoring
Migrate OidcTokenProvider to extend BaseOidcTokenProvider, implementing only the abstract hook methods:
const { BaseOidcTokenProvider, REFRESH_FACTOR, MIN_REFRESH_MARGIN_SECS } = require('./oidc-token-provider-base');
class OidcTokenProvider extends BaseOidcTokenProvider {
constructor(config) {
super('oidc', config); // base handles retry/timer state
// Azure-specific fields only
this._tenantId = config.tenantId;
this._clientId = config.clientId;
this._oidcAudience = config.oidcAudience || 'api://AzureADTokenExchange';
this._azureScope = config.azureScope || '(cognitiveservices.azure.com/redacted)
this._loginHost = this._resolveLoginHost(config.azureCloud);
this._requestUrl = config.requestUrl;
this._requestToken = config.requestToken;
this._cachedToken = null;
}
getToken() { return this._getCachedValue(); }
_getCachedValue() { return this._cachedToken; }
async _doRefresh() {
// existing _refreshToken() logic → updates this._cachedToken / this._expiresAt
}
_getInitSuccessLogContext() { ... }
_getInitFailureLogContext() { ... }
}
The _scheduleRefresh, initialize, isReady, and shutdown methods are then deleted from this file entirely.
Affected Files
containers/api-proxy/oidc-token-provider.js — lines 42–270 (class body)
containers/api-proxy/oidc-token-provider-base.js — provides the base that AWS and GCP already use
Effort Estimate
Medium (refactor + update existing tests in oidc-token-provider.test.js)
Detected by Duplicate Code Detector workflow. Run date: 2026-05-15
Generated by Duplicate Code Detector · ● 18.9M · ◷
Duplicate Code Opportunity
Summary
OidcTokenProvider(Azure OIDC) manually reimplements the same token lifecycle methods —initialize(),isReady(),shutdown(),_scheduleRefresh(),_sleep(), and all the associated state variables — that already exist inBaseOidcTokenProvider. The AWS and GCP providers already extendBaseOidcTokenProvider; the Azure provider was not migrated.containers/api-proxy/oidc-token-provider.js(lines 42–270) vscontainers/api-proxy/oidc-token-provider-base.js(entire file)BaseOidcTokenProvider(e.g. retry logic, shutdown safety, refresh scheduling) must also be applied manually toOidcTokenProvideror it silently diverges.Evidence
oidc-token-provider-base.js(BaseOidcTokenProvider) — already extracted:oidc-token-provider.js(OidcTokenProvider / Azure) — duplicate copy:Meanwhile
AwsOidcTokenProviderandGcpOidcTokenProviderdo extendBaseOidcTokenProvider:Suggested Refactoring
Migrate
OidcTokenProviderto extendBaseOidcTokenProvider, implementing only the abstract hook methods:The
_scheduleRefresh,initialize,isReady, andshutdownmethods are then deleted from this file entirely.Affected Files
containers/api-proxy/oidc-token-provider.js— lines 42–270 (class body)containers/api-proxy/oidc-token-provider-base.js— provides the base that AWS and GCP already useEffort Estimate
Medium (refactor + update existing tests in
oidc-token-provider.test.js)Detected by Duplicate Code Detector workflow. Run date: 2026-05-15