Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions containers/api-proxy/oidc-adapter-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,34 @@ function resolveOidcAuthHeaders({ oidcProvider, awsOidcProvider, buildOidcHeader
return null;
}

/**
* Resolve auth headers with automatic static-key fallback.
*
* Combines OIDC resolution with a static-key fallback into a single call,
* encapsulating the repeated pattern across provider adapters:
* 1. If OIDC provider has a token → use buildOidcHeaders(token)
* 2. If OIDC is configured but no token yet → return empty {} (fail-safe)
* 3. If no OIDC → return staticHeaders
*
* @param {object} opts
* @param {{ getToken: () => (string|undefined|null) }|null|undefined} [opts.oidcProvider]
* @param {unknown} [opts.awsOidcProvider]
* @param {(token: string) => Record<string, string>} opts.buildOidcHeaders
* @param {Record<string, string>} opts.staticHeaders - Headers to use when no OIDC is configured
* @returns {Record<string, string>}
*/
function resolveAuthHeadersWithFallback({ oidcProvider, awsOidcProvider, buildOidcHeaders, staticHeaders }) {
const oidcHeaders = resolveOidcAuthHeaders({ oidcProvider, awsOidcProvider, buildOidcHeaders });
if (oidcHeaders !== null) {
return oidcHeaders;
}
return staticHeaders;
}
Comment on lines +107 to +113

module.exports = {
isValidHeaderName,
validateAuthHeaderEnv,
createOidcRuntimeAdapterMethods,
resolveOidcAuthHeaders,
resolveAuthHeadersWithFallback,
};
40 changes: 20 additions & 20 deletions containers/api-proxy/providers/anthropic.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const {
const {
validateAuthHeaderEnv,
resolveOidcAuthHeaders,
resolveAuthHeadersWithFallback,
} = require('../oidc-adapter-utils');
const { createBaseAdapterConfig, createAdapterMethods, buildProviderAdapter } = require('../adapter-factory');
const { AnthropicOidcTokenProvider } = require('../anthropic-oidc-token-provider');
Expand Down Expand Up @@ -127,20 +128,16 @@ function createAnthropicAdapter(env, deps = {}) {
validationPath: '/v1/messages',
validationMethod: 'POST',
validationBody: '{}',
validationHeaders: () => {
if (oidcProvider && oidcProvider.isReady()) {
return {
'Authorization': `Bearer ${oidcProvider.getToken()}`,
'anthropic-version': '2023-06-01',
'content-type': 'application/json',
};
}
return {
[authHeaderName]: apiKey,
'anthropic-version': '2023-06-01',
'content-type': 'application/json',
};
},
validationHeaders: () => ({
...resolveAuthHeadersWithFallback({
oidcProvider,
awsOidcProvider: null,
buildOidcHeaders: (token) => ({ 'Authorization': `Bearer ${token}` }),
staticHeaders: { [authHeaderName]: apiKey },
}),
'anthropic-version': '2023-06-01',
'content-type': 'application/json',
}),
validationSkip: () => {
if (!oidcConfigured) return null;
// After OIDC init, validate using the acquired token
Expand All @@ -149,12 +146,15 @@ function createAnthropicAdapter(env, deps = {}) {
},
skipModelsFetch: () => oidcConfigured && !oidcProvider?.isReady(),
modelsPath: '/v1/models',
modelsFetchHeaders: () => {
if (oidcProvider && oidcProvider.isReady()) {
return { 'Authorization': `Bearer ${oidcProvider.getToken()}`, 'anthropic-version': '2023-06-01' };
}
return { [authHeaderName]: apiKey, 'anthropic-version': '2023-06-01' };
},
modelsFetchHeaders: () => ({
...resolveAuthHeadersWithFallback({
oidcProvider,
awsOidcProvider: null,
buildOidcHeaders: (token) => ({ 'Authorization': `Bearer ${token}` }),
staticHeaders: { [authHeaderName]: apiKey },
}),
'anthropic-version': '2023-06-01',
}),
reflectionConfigured: !!apiKey || oidcRequested,
reflectionExtra: () => ({
auth_type: oidcRequested ? 'github-oidc/anthropic' : 'static-key',
Expand Down
36 changes: 36 additions & 0 deletions containers/api-proxy/proxy-utils.oidc.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const {
validateAuthHeaderEnv,
createOidcRuntimeAdapterMethods,
resolveOidcAuthHeaders,
resolveAuthHeadersWithFallback,
} = require('./oidc-adapter-utils');

describe('isValidHeaderName', () => {
Expand Down Expand Up @@ -106,3 +107,38 @@ describe('resolveOidcAuthHeaders', () => {
expect(headers).toEqual({ Authorization: 'Bearer bearer-oidc-token' });
});
});

describe('resolveAuthHeadersWithFallback', () => {
it('returns OIDC headers when token is available', () => {
const headers = resolveAuthHeadersWithFallback({
oidcProvider: { getToken: () => 'oidc-token' },
awsOidcProvider: null,
buildOidcHeaders: (token) => ({ Authorization: ['oidc', token].join(':') }),
staticHeaders: { 'x-api-key': 'static-token' },
});

expect(headers).toEqual({ Authorization: 'oidc:oidc-token' });
});

it('returns an empty object when OIDC is configured but token is unavailable', () => {
const headers = resolveAuthHeadersWithFallback({
oidcProvider: { getToken: () => '' },
awsOidcProvider: null,
buildOidcHeaders: () => ({ Authorization: 'ignored-token' }),
staticHeaders: { 'x-api-key': 'static-token' },
});

expect(headers).toEqual({});
});

it('falls back to static headers when OIDC is not configured', () => {
const headers = resolveAuthHeadersWithFallback({
oidcProvider: null,
awsOidcProvider: null,
buildOidcHeaders: () => ({ Authorization: 'ignored-token' }),
staticHeaders: { 'x-api-key': 'static-token' },
});

expect(headers).toEqual({ 'x-api-key': 'static-token' });
});
});
Loading