🔐 feat: Implement Entra ID authentication for Azure OpenAI integration

- Added support for Entra ID authentication in OpenAIClient and related services.
- Updated header management to conditionally use Entra ID access tokens or API keys based on environment configuration.
- Introduced utility functions for Entra ID token retrieval and credential management.
- Enhanced tests to verify Entra ID authentication flow and its integration with Azure configurations.
This commit is contained in:
victorbjorkgren 2025-09-12 17:29:43 +02:00 committed by victorbjor
parent a1471c2f37
commit 9288e84454
9 changed files with 212 additions and 18 deletions

View file

@ -1,6 +1,12 @@
const OpenAI = require('openai');
const { ProxyAgent } = require('undici');
const { constructAzureURL, isUserProvided, resolveHeaders } = require('@librechat/api');
const {
constructAzureURL,
isUserProvided,
resolveHeaders,
shouldUseEntraId,
getEntraIdAccessToken,
} = require('@librechat/api');
const { ErrorTypes, EModelEndpoint, mapModelToAzureConfig } = require('librechat-data-provider');
const {
checkUserKeyExpiry,
@ -108,12 +114,19 @@ const initializeClient = async ({ req, res, version, endpointOption, initAppClie
azureOptions,
});
apiKey = azureOptions.azureOpenAIApiKey;
// For Entra ID, we need to get the actual access token
if (shouldUseEntraId()) {
apiKey = 'entra-id-placeholder';
headers['Authorization'] = `Bearer ${await getEntraIdAccessToken()}`;
} else {
apiKey = azureOptions.azureOpenAIApiKey;
headers['api-key'] = apiKey;
}
opts.defaultQuery = { 'api-version': azureOptions.azureOpenAIApiVersion };
opts.defaultHeaders = resolveHeaders({
headers: {
...headers,
'api-key': apiKey,
'OpenAI-Beta': `assistants=${version}`,
},
user: req.user,
@ -137,7 +150,11 @@ const initializeClient = async ({ req, res, version, endpointOption, initAppClie
clientOptions.defaultQuery = azureOptions.azureOpenAIApiVersion
? { 'api-version': azureOptions.azureOpenAIApiVersion }
: undefined;
clientOptions.headers['api-key'] = apiKey;
if (shouldUseEntraId()) {
clientOptions.headers['Authorization'] = `Bearer ${await getEntraIdAccessToken()}`;
} else {
clientOptions.headers['api-key'] = apiKey;
}
}
}
}