Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion plugins/azure/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export interface AzureCredentials {
resourceName: string;
azureAuthMode: 'apiKey' | 'entra' | 'managed';
azureAuthMode: 'apiKey' | 'entra' | 'managed' | 'azure_cli';
apiKey?: string;
clientId?: string;
clientSecret?: string;
Expand Down
40 changes: 40 additions & 0 deletions plugins/azure/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,42 @@ export async function getAzureManagedIdentityToken(
return result;
}

export function getAzureCliToken(
scope = 'https://cognitiveservices.azure.com/.default',
check: string
): { token: string; error: string | null } {
const result: { token: string; error: string | null } = {
token: '',
error: null,
};

try {
// Note: Azure CLI auth only works in Node.js runtime
// This will not work in Cloudflare Workers or other edge runtimes
if (typeof process === 'undefined' || !process.versions?.node) {
result.error = 'Azure CLI authentication requires Node.js runtime';
return result;
}

const { execSync } = require('child_process');

// Execute Azure CLI command to get access token
const command = `az account get-access-token --resource ${scope.replace('/.default', '')}`;
const output = execSync(command, { encoding: 'utf-8' });

const tokenData = JSON.parse(output);
result.token = tokenData.accessToken;
} catch (error: any) {
result.error = error?.message || String(error);
console.error('getAzureCliToken error: ', result.error);
console.error(
'Make sure Azure CLI is installed and you are logged in using "az login"'
);
}

return result;
}

export const getAccessToken = async (
credentials: AzureCredentials,
check: string,
Expand Down Expand Up @@ -142,5 +178,9 @@ export const getAccessToken = async (
);
}

if (azureAuthMode === 'azure_cli') {
tokenResult = getAzureCliToken(scope, check);
}

return tokenResult;
};
11 changes: 11 additions & 0 deletions src/providers/azure-ai-inference/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
getAccessTokenFromEntraId,
getAzureManagedIdentityToken,
getAzureWorkloadIdentityToken,
getAzureCliToken,
} from '../azure-openai/utils';
import { ProviderAPIConfig } from '../types';

Expand Down Expand Up @@ -131,6 +132,16 @@ const AzureAIInferenceAPI: ProviderAPIConfig = {
}
}

// Azure CLI authentication mode - only available in Node.js runtime
if (azureAuthMode === 'azure_cli' && runtime === 'node') {
const scope = 'https://cognitiveservices.azure.com/.default';
const accessToken = getAzureCliToken(scope);
if (accessToken) {
headers['Authorization'] = `Bearer ${accessToken}`;
return headers;
}
}

if (apiKey) {
headers['Authorization'] = `Bearer ${apiKey}`;
return headers;
Expand Down
11 changes: 11 additions & 0 deletions src/providers/azure-openai/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
getAccessTokenFromEntraId,
getAzureManagedIdentityToken,
getAzureWorkloadIdentityToken,
getAzureCliToken,
} from './utils';
import { getRuntimeKey } from 'hono/adapter';

Expand Down Expand Up @@ -77,6 +78,16 @@ const AzureOpenAIAPIConfig: ProviderAPIConfig = {
}
}
}
// Azure CLI authentication mode - only available in Node.js runtime
if (azureAuthMode === 'azure_cli' && runtime === 'node') {
const scope = 'https://cognitiveservices.azure.com/.default';
const accessToken = getAzureCliToken(scope);
if (accessToken) {
return {
Authorization: `Bearer ${accessToken}`,
};
}
}
const headersObj: Record<string, string> = {
'api-key': `${apiKey}`,
};
Expand Down
20 changes: 20 additions & 0 deletions src/providers/azure-openai/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AZURE_OPEN_AI } from '../../globals';
import { OpenAIErrorResponseTransform } from '../openai/utils';
import { ErrorResponse } from '../types';
import { execSync } from 'child_process';

export async function getAccessTokenFromEntraId(
tenantId: string,
Expand Down Expand Up @@ -105,6 +106,25 @@ export async function getAzureWorkloadIdentityToken(
}
}

export function getAzureCliToken(
scope = 'https://cognitiveservices.azure.com/.default'
): string | undefined {
try {
// Execute Azure CLI command to get access token
const command = `az account get-access-token --resource ${scope.replace('/.default', '')}`;
const output = execSync(command, { encoding: 'utf-8' });

const tokenData = JSON.parse(output);
return tokenData.accessToken;
} catch (error: any) {
console.error('getAzureCliToken error: ', error?.message || error);
console.error(
'Make sure Azure CLI is installed and you are logged in using "az login"'
);
return undefined;
}
}

export const AzureOpenAIFinetuneResponseTransform = (
response: Response | ErrorResponse,
responseStatus: number
Expand Down
3 changes: 3 additions & 0 deletions src/types/requestBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export interface Options {
deploymentId?: string;
apiVersion?: string;
adAuth?: string;
/** Azure authentication mode: 'apiKey' | 'entra' | 'managed' | 'workload' | 'azure_cli' */
azureAuthMode?: string;
azureManagedClientId?: string;
azureWorkloadClientId?: string;
Expand Down Expand Up @@ -193,6 +194,7 @@ export interface Targets {
deploymentId?: string;
apiVersion?: string;
adAuth?: string;
/** Azure authentication mode: 'apiKey' | 'entra' | 'managed' | 'workload' | 'azure_cli' */
azureAuthMode?: string;
azureManagedClientId?: string;
azureEntraClientId?: string;
Expand Down Expand Up @@ -475,6 +477,7 @@ export interface ShortConfig {
deploymentId?: string;
workersAiAccountId?: string;
apiVersion?: string;
/** Azure authentication mode: 'apiKey' | 'entra' | 'managed' | 'workload' | 'azure_cli' */
azureAuthMode?: string;
azureManagedClientId?: string;
azureEntraClientId?: string;
Expand Down