Skip to content

[Duplicate Code] Provider auth header construction is repeated across API proxy adapters #5620

Description

@github-actions

Duplicate Code Opportunity

Summary

  • Pattern: Each API proxy provider adapter hand-builds validation/model/request auth headers, including static credentials, OIDC fallback, unavailable-token handling, and provider-specific extras.
  • Locations: containers/api-proxy/providers/openai.js, anthropic.js, copilot.js, and gemini.js.
  • Impact: More than two copies on the security-critical credential-injection path. The shared createProviderOidcAuth helper reduces setup duplication, but auth header construction and fallback semantics still remain scattered. This overlaps with the completed prior provider scaffolding finding [Duplicate Code] Provider adapter credential scaffolding is repeated across API proxy providers #5197, but the pattern still reproduces.

Evidence

OpenAI defines static header construction and OIDC/static fallback locally:

75  function buildStaticAuthHeaders(key) {
76    if (customAuthHeader) {
77      return { [customAuthHeader]: key };
78    }
79    return { 'Authorization': `Bearer ${key}` };
80  }
...
107    getAuthHeaders() {
108      return resolveAuthHeaders(
109        (token) => (customAuthHeader
110          ? { [customAuthHeader]: token }
111          : { 'Authorization': ['Bearer', token].join(' ') }),
112        buildStaticAuthHeaders(apiKey),
113      );
114    },

Anthropic repeats OIDC readiness/static fallback for validation, model fetch, and request headers:

130    validationHeaders: () => {
131      if (oidcProvider && oidcProvider.isReady()) {
132        return {
133          'Authorization': `Bearer ${oidcProvider.getToken()}`,
134          'anthropic-version': '2023-06-01',
135          'content-type': 'application/json',
136        };
137      }
138      return {
139        [authHeaderName]: apiKey,
140        'anthropic-version': '2023-06-01',
141        'content-type': 'application/json',
142      };
143    },
...
177    getAuthHeaders(req) {
178      const oidcHeaders = resolveOidcAuthHeaders({
179        oidcProvider,
180        awsOidcProvider: null,
181        buildOidcHeaders: (token) => ({ 'Authorization': 'Bearer ' + token }),
182      });
...
192      const headers = oidcHeaders !== null ? { ...oidcHeaders } : { [authHeaderName]: apiKey };

Copilot repeats request-path-specific auth prefix selection plus OIDC/static fallback:

240      const oidcHeaders = resolveOidcAuthHeaders({
241        oidcProvider,
242        awsOidcProvider,
243        buildOidcHeaders: (token) => ({
244          'Authorization': ['Bearer', token].join(' '),
245          'Copilot-Integration-Id': integrationId,
246        }),
247      });
248      if (oidcHeaders !== null) {
249        return oidcHeaders;
250      }
...
253      const authPrefix = (requiresGitHubTokenPrefix && !apiKey) ? 'token' : 'Bearer';
254      return {
255        ...(apiKey ? byokExtraHeaders : {}),
256        'Authorization': [authPrefix, authToken].join(' '),
257        'Copilot-Integration-Id': integrationId,
258      };

Gemini is simpler but still hand-codes the same three surfaces for one credential header:

43    validationPath: '/v1beta/models',
44    validationHeaders: () => ({ 'x-goog-api-key': apiKey }),
45    modelsPath: '/v1beta/models',
46    modelsFetchHeaders: () => ({ 'x-goog-api-key': apiKey }),
...
54    getAuthHeaders() {
55      return { 'x-goog-api-key': apiKey };
56    },

Suggested Refactoring

Add a small auth-header strategy abstraction, for example createAuthHeaderStrategy({ staticHeader, oidcHeader, extraHeaders, unavailableBehavior }), and let provider adapters supply only provider-specific constants and request predicates. Reuse it for validation headers, model fetch headers, and per-request headers so OIDC not-ready behavior and static-key fallback are implemented once.

Affected Files

  • containers/api-proxy/providers/openai.js — lines 75-114
  • containers/api-proxy/providers/anthropic.js — lines 130-192
  • containers/api-proxy/providers/copilot.js — lines 240-258
  • containers/api-proxy/providers/gemini.js — lines 43-56

Effort Estimate

Medium


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

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

  • expires on Jul 27, 2026, 9:59 PM UTC

Metadata

Metadata

Assignees

No one assigned

    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