mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-12 12:25:20 +00:00
feat: Allow Azure OpenAI to authenticate using DefaultAzureCredential
Co-Authored-By: Selene Blok <20491756+selenecodes@users.noreply.github.com>
This commit is contained in:
parent
72cd3a54f7
commit
caf0a1fbb6
2 changed files with 49 additions and 11 deletions
|
|
@ -9,6 +9,8 @@ from aiocache import cached
|
|||
import requests
|
||||
from urllib.parse import quote
|
||||
|
||||
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
|
||||
|
||||
from fastapi import Depends, HTTPException, Request, APIRouter
|
||||
from fastapi.responses import (
|
||||
FileResponse,
|
||||
|
|
@ -182,12 +184,30 @@ def get_headers_and_cookies(
|
|||
if oauth_token:
|
||||
token = f"{oauth_token.get('access_token', '')}"
|
||||
|
||||
elif auth_type in ("azure_ad", "azure_entra_id"):
|
||||
token = get_azure_entra_id_access_token()
|
||||
|
||||
if token:
|
||||
headers["Authorization"] = f"Bearer {token}"
|
||||
|
||||
return headers, cookies
|
||||
|
||||
|
||||
def get_azure_entra_id_access_token():
|
||||
"""
|
||||
Get Azure access token using DefaultAzureCredential for Azure OpenAI.
|
||||
Returns the token string or None if authentication fails.
|
||||
"""
|
||||
try:
|
||||
token_provider = get_bearer_token_provider(
|
||||
DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default"
|
||||
)
|
||||
return token_provider()
|
||||
except Exception as e:
|
||||
log.error(f"Error getting Azure access token: {e}")
|
||||
return None
|
||||
|
||||
|
||||
##########################################
|
||||
#
|
||||
# API routes
|
||||
|
|
@ -641,9 +661,12 @@ async def verify_connection(
|
|||
)
|
||||
|
||||
if api_config.get("azure", False):
|
||||
headers["api-key"] = key
|
||||
api_version = api_config.get("api_version", "") or "2023-03-15-preview"
|
||||
# Only set api-key header if not using Azure Entra ID authentication
|
||||
auth_type = api_config.get("auth_type", "bearer")
|
||||
if auth_type not in ("azure_ad", "azure_entra_id"):
|
||||
headers["api-key"] = key
|
||||
|
||||
api_version = api_config.get("api_version", "") or "2023-03-15-preview"
|
||||
async with session.get(
|
||||
url=f"{url}/openai/models?api-version={api_version}",
|
||||
headers=headers,
|
||||
|
|
@ -885,7 +908,12 @@ async def generate_chat_completion(
|
|||
if api_config.get("azure", False):
|
||||
api_version = api_config.get("api_version", "2023-03-15-preview")
|
||||
request_url, payload = convert_to_azure_payload(url, payload, api_version)
|
||||
headers["api-key"] = key
|
||||
|
||||
# Only set api-key header if not using Azure Entra ID authentication
|
||||
auth_type = api_config.get("auth_type", "bearer")
|
||||
if auth_type not in ("azure_ad", "azure_entra_id"):
|
||||
headers["api-key"] = key
|
||||
|
||||
headers["api-version"] = api_version
|
||||
request_url = f"{request_url}/chat/completions?api-version={api_version}"
|
||||
else:
|
||||
|
|
@ -1058,7 +1086,12 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)):
|
|||
|
||||
if api_config.get("azure", False):
|
||||
api_version = api_config.get("api_version", "2023-03-15-preview")
|
||||
headers["api-key"] = key
|
||||
|
||||
# Only set api-key header if not using Azure Entra ID authentication
|
||||
auth_type = api_config.get("auth_type", "bearer")
|
||||
if auth_type not in ("azure_ad", "azure_entra_id"):
|
||||
headers["api-key"] = key
|
||||
|
||||
headers["api-version"] = api_version
|
||||
|
||||
payload = json.loads(body)
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
if (!key && !['azure_ad', 'azure_entra_id'].includes(auth_type)) {
|
||||
loading = false;
|
||||
|
||||
toast.error($i18n.t('Key is required'));
|
||||
|
|
@ -331,6 +331,9 @@
|
|||
<option value="session">{$i18n.t('Session')}</option>
|
||||
{#if !direct}
|
||||
<option value="system_oauth">{$i18n.t('OAuth')}</option>
|
||||
{#if azure}
|
||||
<option value="azure_entra_id">{$i18n.t('Azure Entra ID')}</option>
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
</select>
|
||||
|
|
@ -361,6 +364,12 @@
|
|||
>
|
||||
{$i18n.t('Forwards system user OAuth access token to authenticate')}
|
||||
</div>
|
||||
{:else if ['azure_ad', 'azure_entra_id'].includes(auth_type)}
|
||||
<div
|
||||
class={`text-xs self-center translate-y-[1px] ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
|
||||
>
|
||||
{$i18n.t('Uses DefaultAzureCredential to authenticate')}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -443,7 +452,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-col w-full">
|
||||
<div class="flex flex-col w-full mt-2">
|
||||
<div class="mb-1 flex justify-between">
|
||||
<div
|
||||
class={`mb-0.5 text-xs text-gray-500
|
||||
|
|
@ -499,8 +508,6 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<hr class=" border-gray-100 dark:border-gray-700/10 my-1.5 w-full" />
|
||||
|
||||
<div class="flex items-center">
|
||||
<label class="sr-only" for="add-model-id-input">{$i18n.t('Add a model ID')}</label>
|
||||
<input
|
||||
|
|
@ -528,9 +535,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<hr class=" border-gray-50 dark:border-gray-850 my-2.5 w-full" />
|
||||
|
||||
<div class="flex gap-2">
|
||||
<div class="flex gap-2 mt-2">
|
||||
<div class="flex flex-col w-full">
|
||||
<div
|
||||
class={`mb-0.5 text-xs text-gray-500
|
||||
|
|
|
|||
Loading…
Reference in a new issue