Home / AI & GenAI

AI & GenAIHow-toBeginner

Azure OpenAI first call from Python: use Entra ID and get the deployment name right

Make your first Azure OpenAI call from Python without an API key. Find your endpoint and deployment name, assign the right role, sign in with Entra ID, and fix the 401, 403, 404 and 429 errors beginners hit.

Deepak Bhardwaj5 min read

Applies toAzure OpenAI in Azure AI Foundry, openai Python SDK 1.x, azure-identity, Azure CLI 2.x

The goal

You have an Azure OpenAI resource, and you want to call a model from Python. Most first-time failures come from two things: confusing the model name with the deployment name, and assuming that being an Owner lets you call the API.

Three names to get straight

Name Example Used for
Resource name aoai-ops-demo Part of the endpoint URL
Model name The model you chose, such as gpt-4o-mini Only tells you what's deployed
Deployment name chat-prod This is what you pass as model in code

You choose the deployment name when you deploy a model. It doesn't have to match the model's name.

Step 1: find the endpoint and deployment

az login

az cognitiveservices account show \
  --name aoai-ops-demo --resource-group rg-ai \
  --query "{endpoint:properties.endpoint, disableLocalAuth:properties.disableLocalAuth}"

az cognitiveservices account deployment list \
  --name aoai-ops-demo --resource-group rg-ai \
  --query "[].{deployment:name, model:properties.model.name, version:properties.model.version, capacity:sku.capacity}" \
  -o table

No deployments listed? You can't call a model until you create one. Do that in the Foundry portal, or read the CLI cheat sheet.

Step 2: give yourself the right role

Calling the model is a data-plane action, so it needs its own role. Owner and Contributor alone don't include it.

RESOURCE_ID=$(az cognitiveservices account show \
  --name aoai-ops-demo --resource-group rg-ai --query id -o tsv)

az role assignment create \
  --role "Cognitive Services OpenAI User" \
  --assignee "you@contoso.com" \
  --scope "$RESOURCE_ID"

Allow a few minutes for this to apply. For an app in Azure, assign the same role to its managed identity.

Step 3: test with curl

This proves that your access works, separately from any Python problems:

TOKEN=$(az account get-access-token --resource https://cognitiveservices.azure.com --query accessToken -o tsv)

curl -s "https://aoai-ops-demo.openai.azure.com/openai/deployments/chat-prod/chat/completions?api-version=2024-10-21" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"Say hello in five words."}],"max_tokens":30}'

Step 4: call it from Python

python -m venv .venv
source .venv/bin/activate      # Windows: .venv\Scripts\activate
pip install openai azure-identity
import os
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
from openai import AzureOpenAI

token_provider = get_bearer_token_provider(
    DefaultAzureCredential(),
    "https://cognitiveservices.azure.com/.default",
)

client = AzureOpenAI(
    azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
    azure_ad_token_provider=token_provider,
    api_version="2024-10-21",
)

response = client.chat.completions.create(
    model=os.environ["AZURE_OPENAI_DEPLOYMENT"],   # deployment name, not model name
    messages=[
        {"role": "system", "content": "You answer IT questions in one short sentence."},
        {"role": "user", "content": "What does DNS do?"},
    ],
    max_tokens=100,
)

print(response.choices[0].message.content)
print(response.usage)

Run it:

export AZURE_OPENAI_ENDPOINT="https://aoai-ops-demo.openai.azure.com/"
export AZURE_OPENAI_DEPLOYMENT="chat-prod"
python first_call.py

DefaultAzureCredential tries several sign-in methods in turn. On a laptop it finds your az login session. In Azure it finds the managed identity. So your code doesn't need to change, and there's no key to leak.

API versions change over time, and some newer models and features need a newer one. Check Microsoft's API version list, and consider the newer v1 API path if your setup supports it.

Some newer models reject max_tokens and require max_completion_tokens. If you see that error, change the parameter name.

Step 5: fix errors

Status Message Cause Fix
404 DeploymentNotFound The name's wrong, it's in another resource, or it was just created Use the deployment name from Step 1; wait a few minutes
401 Access token is missing or invalid / wrong audience Bad token scope or tenant Use cognitiveservices.azure.com, and check az account show
403 PermissionDenied / principal lacks the action The data-plane role is missing Add Cognitive Services OpenAI User
403 Traffic is not from an approved network The resource firewall or a private endpoint is in the way Connect from an allowed network; see private endpoints
400 Unsupported parameter or api-version errors The model or API version doesn't support it Check the version and the parameter names
400 Content filter The prompt or answer was blocked See content filter errors
429 Too Many Requests Deployment quota reached Retry with backoff; see throttling

When DefaultAzureCredential itself fails, it prints a list of each method it tried. Read through it. On a laptop, the fix is usually az login, perhaps with --tenant, because you're signed in to the wrong tenant.

Tip

Copy the endpoint exactly as the portal shows it. Foundry may also show a different URL style. Use the endpoint of the resource holding your deployment, because deployments aren't shared between resources.

Why not use an API key?

A key is quicker to try, but anyone who has it can use your quota, and it doesn't show who made a call.

Warning

If a team must use a key for now, keep it in Key Vault, never in code or Git. Once everyone uses Entra ID, turn off keys with disableLocalAuth. Check first that nothing still depends on them, because they stop working immediately. See key rotation and moving to Entra ID.

Add a simple retry

Quota errors are normal on shared deployments, so don't fail on the first one. The SDK retries some errors on its own, and you can adjust it:

client = AzureOpenAI(
    azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
    azure_ad_token_provider=token_provider,
    api_version="2024-10-21",
    max_retries=4,
    timeout=60,
)

Always set a timeout, so that a stuck call can't hang your app.

Prevent it next time

  • Use the same deployment name in each environment, and keep it in configuration rather than code.
  • Plan for model retirements, because models and versions do get retired.
  • Log response.usage to track spending. See estimating token costs.
  • Learn more about prompts and parameters in LLM API basics.