Skip to content

[Duplicate Code] Provider adapter auth-header scaffolding repeated across API proxy providers #5736

Description

@github-actions

Duplicate Code Opportunity

Summary

Evidence

containers/api-proxy/providers/openai.js lines 30-125:

function createOpenAIAdapter(env, deps = {}) {
  const { apiKey: openaiApiKey, rawTarget: openaiTarget, basePath: openaiBasePath } = createBaseAdapterConfig(env, {
    keyEnvVar: OPENAI_ENV.KEY,
    targetEnvVar: OPENAI_ENV.TARGET,
    basePathEnvVar: OPENAI_ENV.BASE_PATH,
    defaultTarget: 'api.openai.com',
  });
  // ...provider-specific target resolution...
  const bodyTransform = deps.bodyTransform || null;
  const { authProvider, oidcConfigured, runtimeMethods: oidcRuntimeMethods, validationSkip, skipModelsFetch, resolveAuthHeaders } = createProviderOidcAuth(env, { staticAuthToken: apiKey });
  function buildStaticAuthHeaders(key) {
    if (customAuthHeader) return { [customAuthHeader]: key };
    return { 'Authorization': `Bearer ${key}` };
  }
  const adapterMethods = createAdapterMethods({
    apiKey, rawTarget, basePath, provider: 'openai', port: 10000,
    validationHeaders: () => buildStaticAuthHeaders(apiKey),
    modelsFetchHeaders: () => buildStaticAuthHeaders(apiKey),
  });
  return buildProviderAdapter({
    name: 'openai', port: 10000, adapterMethods,
    getAuthHeaders() { return resolveAuthHeaders(/* token headers */, buildStaticAuthHeaders(apiKey)); },
    bodyTransform,
  });
}

containers/api-proxy/providers/anthropic.js lines 50-150:

function createAnthropicAdapter(env, deps = {}) {
  const { apiKey, rawTarget, basePath } = createBaseAdapterConfig(env, {
    keyEnvVar: ANTHROPIC_ENV.KEY,
    targetEnvVar: ANTHROPIC_ENV.TARGET,
    basePathEnvVar: ANTHROPIC_ENV.BASE_PATH,
    defaultTarget: 'api.anthropic.com',
  });
  const authHeaderName = validateAuthHeaderEnv(ANTHROPIC_ENV.AUTH_HEADER, env[ANTHROPIC_ENV.AUTH_HEADER], 'x-api-key');
  const { oidcProvider, oidcConfigured, runtimeMethods: oidcRuntimeMethods } = createProviderOidcAuth(env, { staticAuthToken: apiKey, oidcProviderFactory: /* ... */ });
  const bodyTransform = deps.bodyTransform || null;
  const adapterMethods = createAdapterMethods({
    apiKey, rawTarget, basePath, provider: 'anthropic', port: 10001,
    validationHeaders: () => ({
      ...resolveAuthHeadersWithFallback({ buildOidcHeaders: (token) => ({ 'Authorization': `Bearer ${token}` }), staticHeaders: { [authHeaderName]: apiKey } }),
      'anthropic-version': '2023-06-01',
    }),
    modelsFetchHeaders: () => ({ ...resolveAuthHeadersWithFallback(/* same auth inputs */) }),
  });
}

containers/api-proxy/providers/gemini.js lines 27-73:

function createGeminiAdapter(env, deps = {}) {
  const { apiKey, rawTarget, basePath } = createBaseAdapterConfig(env, {
    keyEnvVar: GEMINI_ENV.KEY,
    targetEnvVar: GEMINI_ENV.TARGET,
    basePathEnvVar: GEMINI_ENV.BASE_PATH,
    defaultTarget: 'generativelanguage.googleapis.com',
  });
  const bodyTransform = deps.bodyTransform || null;
  const adapterMethods = createAdapterMethods({
    apiKey, rawTarget, basePath, provider: 'gemini', port: 10003,
    validationHeaders: () => ({ 'x-goog-api-key': apiKey }),
    modelsFetchHeaders: () => ({ 'x-goog-api-key': apiKey }),
  });
  return buildProviderAdapter({
    name: 'gemini', port: 10003, adapterMethods,
    getAuthHeaders() { return { 'x-goog-api-key': apiKey }; },
    bodyTransform,
  });
}

Suggested Refactoring

Add a shared provider-auth helper near containers/api-proxy/adapter-factory.js, for example createProviderAuthScaffold({ env, envVars, defaults, headerBuilder, oidc, validation, models }), that returns { apiKey, rawTarget, basePath, bodyTransform, adapterMethods, getAuthHeaders }. Provider modules would supply only provider-specific target overrides, headers, transforms, and unconfigured responses.

Affected Files

  • containers/api-proxy/providers/openai.js — lines 30-125
  • containers/api-proxy/providers/anthropic.js — lines 50-150
  • containers/api-proxy/providers/gemini.js — lines 27-73

Effort Estimate

Medium


Detected by Duplicate Code Detector workflow. Run date: 2026-06-30

Generated by Duplicate Code Detector · 105.8 AIC · ⊞ 23.1K ·

  • expires on Jul 30, 2026, 10:07 PM UTC

Metadata

Metadata

Assignees

Type

No type

Fields

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