Skip to content

Add azure provider with Entra ID auth - #20

Merged
tiberiuana merged 4 commits into
mainfrom
feat/entra-token-auth
Oct 19, 2026
Merged

tiberiuana merged 4 commits into
mainfrom
feat/entra-token-auth

Conversation

@tiberiuana

@tiberiuana tiberiuana commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

What

New model provider azure for OpenAI models on Azure Foundry / Azure OpenAI. It authenticates with Microsoft Entra ID tokens instead of API keys.

model:
  provider: azure
  name: <deployment-name>
  baseUrl: https://<resource>.openai.azure.com/openai

Why

For Azure deployments (Container Apps, AKS) where key auth is disabled on the Foundry resource. The identity comes from the environment, and tokens are refreshed automatically. Nothing changes between environments:

  • Container Apps: managed identity
  • AKS: workload identity
  • Local: az login

Notes

  • The identity needs the Cognitive Services OpenAI User role on the resource.
  • @ai-sdk/azure is pinned exactly to 4.0.11 to match the other @ai-sdk packages. Newer versions fail typecheck.
  • baseUrl must be https://<resource>.openai.azure.com/openai; other hosts or a trailing /v1 build a wrong URL. See the user guide.
  • Tested against a dev Foundry resource with /ready?deep=1.
  • Plan: docs/specs/016_azure_entra_auth_plan.md. Setup: docs/user-guide.md → "Azure Foundry (Entra ID)".

🤖 Generated with Claude Code

Foundry has key auth disabled; spec an azure provider that authenticates via
Entra ID tokens so the agent can run on Container Apps and AKS.
A static Entra token in OPENAI_API_KEY works but cannot refresh; document it
as a pre-implementation check of network, RBAC and deployment.
Foundry has key auth disabled. The azure provider gets tokens from
DefaultAzureCredential (managed identity, AKS workload identity, az login) and
lets @ai-sdk/azure send and refresh them; no API key is needed.
Explain the config, identity per environment, the required role and env vars;
align spec 016 with the /openai baseUrl form and the pinned SDK version.
@github-actions

Copy link
Copy Markdown
Contributor

QualOps Code Quality Analysis

Status: ⚠️ FAILED - Critical or high severity issues found

Summary

  • Total Issues: 5
  • Critical: 1 🔴
  • High: 1 🟠
  • Medium: 1 🟡
  • Low: 2 🟢
  • Files Analyzed: 12

🔴 Critical Issues (1)

  • CHANGELOG.md:2163 - security
    @ai-sdk/[email protected] lists @ai-sdk/[email protected] as a resolved dependency in the lockfile, which does not match the legitimate Vercel AI SDK package

🟠 High Issues (1)

  • CHANGELOG.md:25 - bug
    cfg.baseUrl is typed string | undefined at the TypeScript level and is passed directly to createAzure without a non-null assertion or type guard

🟡 Medium Issues (1)

  • CHANGELOG.md:15 - bug
    Module-level azureTokenProvider singleton is never reset, causing test isolation problems and preventing credential refresh on config changes within a process

📊 Full Report

View detailed report


Powered by QualOps

@tiberiuana

Copy link
Copy Markdown
Contributor Author

QualOps triage

Note: QualOps attaches every finding to CHANGELOG.md, so its file and line numbers are wrong.

  1. Critical: @ai-sdk/[email protected] is not a legitimate dependency. Ignore, false positive.
    • The published @ai-sdk/[email protected] declares "@ai-sdk/deepseek": "3.0.7" as a dependency and imports DeepSeekChatLanguageModel from it for azure.deepseek models.
    • On npm, the package comes from github.com/vercel/ai, is published by vercel-release-bot, and has SLSA provenance.
    • The lockfile integrity hash matches the registry.
  2. High: cfg.baseUrl may be undefined when passed to createAzure. Ignore.
    • createAzure accepts baseURL?: string, which is why typecheck passes.
    • The schema refine makes baseUrl required for azure, and buildModel is not part of the library exports, so it always gets a validated config.
    • Without a baseUrl, the SDK falls back to the AZURE_RESOURCE_NAME env var instead of crashing.
  3. Medium: module-level azureTokenProvider is never reset. Ignore.
    • The token scope is fixed and the credential comes from the environment, not the config.
    • The app has no config reload, so there is nothing to reset.
    • getBearerTokenProvider refreshes tokens itself.
    • Tests mock @azure/identity, so the shared provider does not affect them.
  4. Low: vi.stubEnv('AZURE_API_KEY') in the server test. Valid.
    • The line does nothing: with a token provider, the SDK never reads AZURE_API_KEY.
    • To be removed, or kept with a comment saying no key is needed.
  5. Low: the fetch URL assertion in the azure model test. Ignore.
    • The assertion is deliberate: it guards the exact /openai/v1/responses?api-version=v1 URL that the documented baseUrl form depends on.
    • It should fail if an SDK upgrade changes how URLs are built.

@tiberiuana
tiberiuana merged commit f2462e8 into main Oct 19, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants