Skip to main content

Microsoft Foundry

Fabric's azure-foundry provider supports Microsoft Foundry (formerly Azure AI Foundry) and Azure OpenAI. A single Foundry resource can host models with two different wire formats:

  • OpenAI-stylePOST /v1/chat/completions on endpoints like https://<resource>.openai.azure.com/openai/v1. Used for GPT-4.x, GPT-5.x, Llama, Mistral, and most open-weight models.
  • Anthropic-stylePOST /v1/messages on endpoints like https://<resource>.services.ai.azure.com/anthropic. Used when Microsoft Foundry serves Claude models via the Anthropic Messages API format.

The setup wizard probes your endpoint and auto-detects which transport it uses, which deployments are available, and each model's context length.

Prerequisites

  • A Microsoft Foundry or Azure OpenAI resource with at least one deployment
  • The deployment's endpoint URL
  • Either an API key (from the Azure Portal under "Keys and Endpoint") or the Azure AI User RBAC role on the Foundry resource if you plan to use Microsoft Entra ID (the keyless path Microsoft recommends). Some tenants may show the role as Foundry User during Microsoft's rename rollout.

Quick Start

fabric model
# → Select "Azure Foundry"
# → Enter your endpoint URL
# → Choose Authentication:
# 1. API key
# 2. Microsoft Entra ID (managed identity / workload identity / az login)
# → (Entra) Fabric probes DefaultAzureCredential; on success it never asks for a key
# → (API key) Enter your API key
# Fabric probes the endpoint and auto-detects transport + models
# → Pick a model from the list (or type a deployment name manually)

The wizard will:

  1. Sniff the URL path — URLs ending in /anthropic are recognised as Microsoft Foundry Claude routes.
  2. Probe GET <base>/models — if the endpoint returns an OpenAI-shaped model list, Fabric switches to chat_completions and prefills a picker with the returned deployment IDs.
  3. Probe Anthropic Messages shape — fallback for endpoints that do not expose /models but do accept the Anthropic Messages format.
  4. Fall back to manual entry — private/gated endpoints that reject every probe still work; you pick the API mode and type a deployment name by hand.

Context length for the chosen model is resolved via Fabric's standard metadata chain (models.dev, provider metadata, and hardcoded family fallbacks) and stored in config.yaml so the model can size its own context window correctly.

Microsoft recommends keyless authentication with Microsoft Entra ID for production Foundry workloads. Fabric supports Entra ID for both API surfaces:

  • OpenAI-style (api_mode: chat_completions / codex_responses) — GPT-4/5, Llama, Mistral, DeepSeek, etc.
  • Anthropic-style (api_mode: anthropic_messages) — Claude models on Microsoft Foundry.

Foundry's RBAC is per-resource (Azure AI User grants both surfaces; some tenants may display Foundry User) and Microsoft documents the same inference scope (https://ai.azure.com/.default) for both. Under the hood:

  • OpenAI-style uses the OpenAI Python SDK's native callable api_key= contract — the SDK mints a fresh JWT per request automatically.
  • Anthropic-style uses an httpx.Client with a request event hook installed by agent.azure_identity_adapter.build_bearer_http_client, because the Anthropic SDK does not accept callable auth_token natively. The hook rewrites Authorization: Bearer <fresh-jwt> per outbound request. Same Microsoft RBAC, same Foundry scope — the SDK contract is the only difference.

Why use Entra ID?

  • No long-lived API keys to rotate or revoke.
  • RBAC-driven access — grant or remove Azure AI User on the Foundry resource, no config rewrite needed.
  • Access and audit logs are segmented by assignee instead of all callers sharing one static key.
  • Single auth surface for Azure VMs, AKS pods, App Service, Functions, Container Apps, and Foundry Agent Service via managed identity.
  • Workload identity and service-principal flows for CI/CD pipelines.

One-time setup (Azure side)

  1. In the Azure Portal, open your Foundry resource → Access control (IAM)Add → Add role assignment.
  2. Pick the Azure AI User role (or Foundry User if your tenant has the renamed role).
  3. Assign it to:
    • Your user account for local development with az login.
    • A managed identity or workload identity for Azure-hosted compute (recommended for production).
    • A Foundry Agent Service hosted agent's agent identity when Fabric runs inside a hosted agent.
    • A service principal for CI/CD pipelines when workload identity is not available.
  4. Wait ~5 minutes for the role to propagate.

Azure CLI equivalent:

az role assignment create \
--assignee <principal-or-agent-identity-client-id> \
--role "Azure AI User" \
--scope <foundry-resource-id>

One-time setup (Fabric side)

fabric model
# → Select "Azure Foundry"
# → Enter your endpoint URL
# → Authentication: 2 (Microsoft Entra ID)
# → (optional) user-assigned managed identity client ID
# → (optional) Azure tenant ID
# → Fabric probes DefaultAzureCredential() and reports which inner
# credential succeeded (e.g. AzureCliCredential, ManagedIdentityCredential)

The wizard runs a bounded preflight probe (10 s timeout). On failure it offers to "save anyway, validate later" — useful when configuring on a machine that doesn't yet have credentials but will at runtime (e.g. preparing config for a managed-identity deployment).

azure-identity is installed automatically on first use via Fabric's lazy-install path. To pre-install:

pip install azure-identity

Configuration written to config.yaml

model:
provider: azure-foundry
base_url: https://my-resource.openai.azure.com/openai/v1
api_mode: chat_completions
auth_mode: entra_id
default: gpt-4o
context_length: 128000
entra:
scope: https://ai.azure.com/.default # only when overriding the default

Fabric only manages one Entra-specific knob in config.yaml:

  • scope — the OAuth resource scope. Defaults to Microsoft's documented inference scope (https://ai.azure.com/.default). Override only if your resource was provisioned against a non-standard audience.

Everything else (tenant, service principal secret, federated token file, sovereign cloud authority, broker preferences) is read by azure-identity directly from the standard AZURE_* environment variables — see the credential resolution order below. Set those in ~/.fabric/.env or your deployment environment, exactly as Microsoft's SDK reference describes.

No secrets land in ~/.fabric/.env for Entra mode — azure-identity caches tokens in-process (and where available, in your OS keychain / ~/.IdentityService).

Credential resolution order

azure-identity's DefaultAzureCredential walks this chain on each token request, stopping at the first credential that returns a token:

  1. Environment credentialAZURE_TENANT_ID + AZURE_CLIENT_ID + AZURE_CLIENT_SECRET (or AZURE_CLIENT_CERTIFICATE_PATH / AZURE_FEDERATED_TOKEN_FILE).
  2. Workload IdentityAZURE_FEDERATED_TOKEN_FILE (AKS federated tokens / OIDC).
  3. Managed Identity — IMDS endpoint (169.254.169.254) for virtual machines; IDENTITY_ENDPOINT for App Service / Functions / Container Apps. Foundry Agent Service hosted agents use the hosted agent's agent identity.
  4. Visual Studio Code — Azure account extension.
  5. Azure CLIaz login session.
  6. Azure Developer CLIazd auth login.
  7. Azure PowerShellConnect-AzAccount.
  8. Broker (Windows / WSL only) — Web Account Manager.

Interactive browser credential is excluded by default for unattended Fabric runs; use Azure CLI, Azure Developer CLI, managed identity, workload identity, or service principal credentials instead.

Deployment patterns

Local development:

az login
fabric model # pick Azure Foundry → Entra ID
fabric # uses your az login token

Azure VM / Functions / App Service / Container Apps (system-assigned managed identity):

  1. Enable system-assigned identity on the compute resource.
  2. Grant the identity Azure AI User (or Foundry User) on the Foundry resource.
  3. Set model.auth_mode: entra_id in config.yaml — no env vars needed.

Azure VM / Functions / App Service / Container Apps (user-assigned managed identity):

  • Set AZURE_CLIENT_ID to the user-assigned identity's client ID so DefaultAzureCredential picks the right one.

Foundry Agent Service hosted agent:

  • Create the hosted agent and grant that agent's identity Azure AI User (or Foundry User) on the Foundry resource. Fabric uses ManagedIdentityCredential from inside the hosted agent; role assignment belongs on the agent identity, not just the parent project or your user.

AKS Workload Identity (replaces AAD Pod Identity):

  • Annotate the pod's service account with the workload identity client ID.
  • The pod's federated token file is auto-detected via AZURE_FEDERATED_TOKEN_FILE.
  • model.auth_mode: entra_id works without further config changes.

Service principal in CI:

  • Set AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET in the runner env.

Sovereign clouds (Government, China)

Export AZURE_AUTHORITY_HOST (e.g. https://login.microsoftonline.us for Azure Government, https://login.partner.microsoftonline.cn for Azure China). azure-identity reads it directly.

Health checks

fabric doctor runs a 10 s probe against DefaultAzureCredential when model.auth_mode: entra_id, reporting which inner credential won (env vars present, managed identity endpoint reachable, etc.).

fabric auth shows a structured status block:

azure-foundry (Microsoft Entra ID):
Endpoint: https://my-resource.openai.azure.com/openai/v1
Scope: https://ai.azure.com/.default
Status: configured; live token probe is skipped here

Limitations

  • Anthropic-style endpoints use an httpx event hook. The Anthropic Python SDK does not accept a callable auth_token natively (≤ 0.86.0). Fabric installs a request event hook on a custom httpx.Client that mints a fresh JWT per outbound request and rewrites Authorization: Bearer <jwt>. This is functionally equivalent to the OpenAI SDK's native Callable[[], str] contract but adds one indirection layer. If the Anthropic SDK adds first-class callable-auth support in a future release, Fabric will switch to it transparently.
  • Batch jobs and multiprocessing.Pool. The Entra token provider is a closure that cannot be pickled across process boundaries. batch_runner.py automatically drops the callable from the worker config and lets each worker process rebuild its own provider from config.yaml — no user action required, but each worker pays one chain walk at startup.
  • No bearer JWT persistence in auth.json. Fabric does not duplicate azure-identity's internal token cache; cold starts walk the credential chain on first inference.

Configuration (written to config.yaml)

After running the wizard you'll see something like this:

model:
provider: azure-foundry
base_url: https://my-resource.openai.azure.com/openai/v1
api_mode: chat_completions # or "anthropic_messages"
default: gpt-5.4-mini # your deployment / model name
context_length: 400000 # auto-detected

And in ~/.fabric/.env:

AZURE_FOUNDRY_API_KEY=<your-azure-key>

OpenAI-style endpoints (GPT, Llama, etc.)

Azure OpenAI's v1 GA endpoint accepts the standard openai Python client with minimal changes:

model:
provider: azure-foundry
base_url: https://my-resource.openai.azure.com/openai/v1
api_mode: chat_completions
default: gpt-5.4

Important behaviour:

  • GPT-5.x, codex, and o-series auto-route to the Responses API. Microsoft Foundry deploys GPT-5 / codex / o1 / o3 / o4 models as Responses-API-only — calling /chat/completions against them returns 400 "The requested operation is unsupported.". Fabric detects these model families by name and upgrades api_mode to codex_responses transparently, even when config.yaml still reads api_mode: chat_completions. GPT-4, GPT-4o, Llama, Mistral, and other deployments stay on /chat/completions.
  • max_completion_tokens is used automatically. Azure OpenAI (like direct OpenAI) requires max_completion_tokens for gpt-4o, o-series, and gpt-5.x models. Fabric sends the right parameter based on the endpoint.
  • Pre-v1 endpoints that require api-version. If you have a legacy base URL like https://<resource>.openai.azure.com/openai?api-version=2025-04-01-preview, Fabric extracts the query string and forwards it via default_query on every request (the OpenAI SDK otherwise drops it when joining paths).

Anthropic-style endpoints (Claude via Microsoft Foundry)

For Claude deployments, use the Anthropic-style route:

model:
provider: azure-foundry
base_url: https://my-resource.services.ai.azure.com/anthropic
api_mode: anthropic_messages
default: claude-sonnet-4-6

Important behaviour:

  • /v1 is stripped from the base URL. The Anthropic SDK appends /v1/messages to every request URL — Fabric removes any trailing /v1 before handing the URL to the SDK to avoid double-/v1 paths.
  • Modern Foundry routes need no api-version query. https://<resource>.services.ai.azure.com/anthropic follows Microsoft's current Claude Messages API contract directly. Fabric retains api-version=2025-04-15 only for the legacy *.openai.azure.* compatibility route.
  • Static keys use x-api-key; Entra ID uses Bearer. This matches Microsoft's Foundry contract. Fabric's callable Entra token path rewrites Authorization: Bearer <fresh-jwt> per request; a configured AZURE_ANTHROPIC_KEY remains an API key and is never put in the Bearer slot. The legacy *.openai.azure.* compatibility route retains its historical Bearer behavior.
  • 1M context window beta header is kept. Azure still gates the 1M-token Claude context (Opus 4.6/4.7, Sonnet 4.6) behind the anthropic-beta: context-1m-2025-08-07 header. Fabric keeps that beta header on Azure paths; native Anthropic API-key requests do not send it by default.
  • Azure credentials stay Azure-scoped. Use either an Azure-issued static API key or the configured Microsoft Entra ID path described above. Fabric does not use an Anthropic/Claude subscription OAuth credential on Azure (or on native Anthropic) — see NOTICE.

Alternative: provider: anthropic + Azure base URL

If you already have provider: anthropic configured and just want to point it at Microsoft Foundry for Claude, you can skip the azure-foundry provider entirely:

model:
provider: anthropic
base_url: https://my-resource.services.ai.azure.com/anthropic
key_env: AZURE_ANTHROPIC_KEY
default: claude-sonnet-4-6

With AZURE_ANTHROPIC_KEY set in ~/.fabric/.env. Fabric recognizes the trusted Microsoft Foundry host family (*.services.ai.azure.*) together with the /anthropic path and sends the Azure key as x-api-key. A hostname that merely contains azure does not activate Azure credential handling.

key_env is the canonical snake_case field name; api_key_env (and the camelCase keyEnv / apiKeyEnv) are accepted as aliases. If both key_env and AZURE_ANTHROPIC_KEY are set, the key_env-named env var wins. ANTHROPIC_API_KEY remains paired with native Anthropic by default so switching model.base_url cannot leak it to Azure. To use that generic variable with this deployment, also set ANTHROPIC_BASE_URL to the same endpoint; using AZURE_ANTHROPIC_KEY or key_env is clearer.

Model discovery

Azure does not expose a pure-API-key endpoint to list your deployed model deployments. Deployment enumeration requires Azure Resource Manager authentication (az cognitiveservices account deployment list) with an Azure AD principal, not the inference API key.

What Fabric can do:

  • Azure OpenAI v1 endpoints (<resource>.openai.azure.com/openai/v1) expose GET /models with the resource's available model catalog. Fabric uses this list to prefill the model picker.
  • Microsoft Foundry /anthropic routes: detected via URL path, model name entered manually.
  • Private / firewalled endpoints: manual entry with a friendly "couldn't probe" message.

You can always type a deployment name directly — Fabric does not validate against the returned list.

Environment variables

VariablePurpose
AZURE_FOUNDRY_API_KEYPrimary API key for Microsoft Foundry / Azure OpenAI (api_key mode)
AZURE_FOUNDRY_BASE_URLEndpoint URL (set via fabric model; env var is used as a fallback)
AZURE_ANTHROPIC_KEYUsed by provider: anthropic + Azure base URL
AZURE_TENANT_IDEntra ID tenant for service-principal flows
AZURE_CLIENT_IDEntra ID client ID (service principal, workload identity, or user-assigned managed identity)
AZURE_CLIENT_SECRETService principal secret
AZURE_CLIENT_CERTIFICATE_PATHService principal cert (alternative to secret)
AZURE_FEDERATED_TOKEN_FILEWorkload Identity federated token path (AKS)
AZURE_AUTHORITY_HOSTSovereign cloud authority host override
IDENTITY_ENDPOINT / MSI_ENDPOINTManaged Identity endpoint for App Service, Functions, and Container Apps; VMs usually use IMDS instead

The Azure SDK reads the AZURE_* env vars directly. Fabric never inspects them other than to report which sources are present in fabric doctor output.

Troubleshooting

401 Unauthorized on gpt-5.x deployments. Azure serves gpt-5.x on /chat/completions, not /responses. Fabric handles this automatically when the URL contains openai.azure.com, but if you see a 401 with an Invalid API key body, check that api_mode in your config.yaml is chat_completions.

404 on /v1/messages?api-version=.../v1/messages. This is the malformed-URL bug from older Azure Anthropic setups. Upgrade Fabric and remove the query string from model.base_url. Modern *.services.ai.azure.* Foundry routes send no api-version; the legacy *.openai.azure.* compatibility route keeps api-version=2025-04-15 as a real query parameter rather than baking it into the base URL.

Wizard says "Auto-detection incomplete." The endpoint rejected both the /models probe and the Anthropic Messages probe. This is normal for private endpoints behind a firewall or with an IP allow-list. Fall back to manual API mode selection and type your deployment name — everything still works, Fabric just can't prefill the picker.

Wrong transport picked. Run fabric model again and the wizard will re-probe. If the probe still picks the wrong mode, you can edit config.yaml directly:

model:
provider: azure-foundry
api_mode: anthropic_messages # or chat_completions

Entra ID: "credential chain exhausted" or 401 Unauthorized after switching to auth_mode: entra_id.

  • Run az login to refresh your developer session (the cached token may have expired).
  • Verify the Azure AI User (or Foundry User) role assignment took effect: az role assignment list --assignee <user-or-identity-id> should list it on your Foundry resource. Role propagation can take up to 5 minutes.
  • For user-assigned managed identities, double-check AZURE_CLIENT_ID matches the identity attached to the compute resource.
  • Run fabric doctor — the Azure Entra probe reports whether token acquisition succeeded and includes a remediation hint.

Entra ID: wizard preflight hangs or times out. The 10 s preflight is a soft check. Choose "Save anyway and validate later" and run fabric doctor after deploying to the target environment. Common causes include an unreachable token service or stale local login state — prefer workload identity in CI, set AZURE_TENANT_ID+AZURE_CLIENT_ID+AZURE_CLIENT_SECRET when using a service principal, or run az login for local development.

401 on Anthropic-style endpoint with Entra ID. Verify the same Azure AI User (or Foundry User) role is assigned on the Foundry resource (it covers both /openai/v1 and /anthropic paths). If the OpenAI-style probe works during the wizard but claude-* requests fail at runtime, the most common cause is a stale model.entra.scope left over from an earlier wizard run — delete the entra.scope line from config.yaml so the runtime falls back to the default https://ai.azure.com/.default scope.