The Error
You call Azure OpenAI from your .NET application and get this response:
Azure.RequestFailedException: Service request failed.
Status: 401 (Unauthorized)
Content:
{
"statusCode": 401,
"message": "Access denied due to invalid subscription key.
Make sure to provide a valid key for an active subscription."
}
Or, when using token-based authentication:
Azure.Identity.AuthenticationFailedException:
DefaultAzureCredential failed to retrieve a token from the included credentials.
Either way, your request never reaches the model. The service rejected it at the front door.
Root Causes
Five situations produce a 401 when calling Azure OpenAI. They look similar in the logs but have very different fixes.
1. Wrong API Key
The most common cause. You copied the key from the wrong resource, the key was regenerated since you stored it, or there is a whitespace character at the beginning or end of the string.
2. Wrong Endpoint URL
Azure OpenAI endpoints are resource-specific. Using https://my-other-resource.openai.azure.com/ when your deployment lives on https://my-resource.openai.azure.com/ will fail with 401 because the key does not belong to that resource.
3. Wrong Deployment Name
Passing the model name (like gpt-4o) instead of your deployment name (like my-gpt4o-deployment) can produce authorization errors in some API versions. The service cannot route the request to a deployment that does not exist under your resource.
4. Missing RBAC Role
When using DefaultAzureCredential or any token-based authentication, the identity must have the Cognitive Services OpenAI User role on the Azure OpenAI resource. Without it, the token is valid but the authorization check fails — still a 401.
5. DefaultAzureCredential Fallback Chain Issue
DefaultAzureCredential tries multiple credential sources in a fixed order: environment variables, managed identity, Visual Studio, Azure CLI, and others. If the wrong credential resolves first — or none resolve at all — you get a 401 or an AuthenticationFailedException.
Diagnosing the Problem
Before changing code, confirm which root cause you are dealing with.
Step 1: Verify credentials in the Azure portal. Open your Azure OpenAI resource, go to Keys and Endpoint, and confirm the endpoint URL and key values. Copy them fresh.
Step 2: Test with a raw HTTP call. This isolates SDK configuration problems from actual auth failures:
curl -X POST "https://YOUR-RESOURCE.openai.azure.com/openai/deployments/YOUR-DEPLOYMENT/chat/completions?api-version=2024-10-21" \
-H "api-key: YOUR-API-KEY" \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"Hello"}]}'
If curl succeeds but your .NET code fails, the problem is in how the SDK is configured. If curl also returns 401, the problem is with the key, endpoint, or deployment name itself.
Step 3: Check RBAC assignments. In the Azure portal, open your Azure OpenAI resource, go to Access control (IAM), and verify that your identity has the Cognitive Services OpenAI User role.
Fix 1: Correct API Key Authentication
Make sure you are reading the key and endpoint from configuration — never hardcode them:
using Azure;
using Azure.AI.OpenAI;
using OpenAI.Chat;
// Read from configuration (appsettings.json, user-secrets, or env vars)
var endpoint = new Uri(builder.Configuration["AzureOpenAI:Endpoint"]!);
var apiKey = builder.Configuration["AzureOpenAI:ApiKey"]!;
// Create the client with API key auth
var client = new AzureOpenAIClient(endpoint, new AzureKeyCredential(apiKey));
// Use the DEPLOYMENT name, not the model name
ChatClient chatClient = client.GetChatClient("my-gpt4o-deployment");
ChatCompletion completion = await chatClient.CompleteChatAsync("What is .NET?");
Console.WriteLine(completion.Content[0].Text);
Store the API key securely using user-secrets during development:
dotnet user-secrets set "AzureOpenAI:ApiKey" "your-key-here"
dotnet user-secrets set "AzureOpenAI:Endpoint" "https://your-resource.openai.azure.com/"
Fix 2: Managed Identity with DefaultAzureCredential
For production deployments, managed identity is the preferred approach. No keys to leak or rotate.
using Azure.AI.OpenAI;
using Azure.Identity;
using OpenAI.Chat;
var endpoint = new Uri(builder.Configuration["AzureOpenAI:Endpoint"]!);
// DefaultAzureCredential picks up managed identity in Azure,
// and your developer credentials locally
var credential = new DefaultAzureCredential();
var client = new AzureOpenAIClient(endpoint, credential);
ChatClient chatClient = client.GetChatClient("my-gpt4o-deployment");
ChatCompletion completion = await chatClient.CompleteChatAsync("Explain RBAC.");
Console.WriteLine(completion.Content[0].Text);
Before this works, assign the RBAC role. Using the Azure CLI:
# Get your Azure OpenAI resource ID
RESOURCE_ID=$(az cognitiveservices account show \
--name your-openai-resource \
--resource-group your-rg \
--query id -o tsv)
# Assign the role to your identity (user, service principal, or managed identity)
az role assignment create \
--assignee "your-identity-object-id" \
--role "Cognitive Services OpenAI User" \
--scope "$RESOURCE_ID"
Role assignments can take up to 5 minutes to propagate. If the 401 persists immediately after assigning the role, wait and retry.
Fix 3: Pin DefaultAzureCredential to the Right Source
If DefaultAzureCredential picks up the wrong identity, restrict the chain:
// Exclude credential sources you don't need
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
ExcludeEnvironmentCredential = true,
ExcludeVisualStudioCodeCredential = true,
// In production, only use managed identity:
ExcludeManagedIdentityCredential = false,
ExcludeAzureCliCredential = true,
ExcludeSharedTokenCacheCredential = true
});
Or, in production, use ManagedIdentityCredential directly to eliminate any ambiguity:
var credential = new ManagedIdentityCredential();
var client = new AzureOpenAIClient(endpoint, credential);
Fix 4: Verify the Deployment Name
A subtle but frequent mistake. In the Azure portal, open Azure OpenAI Studio and note the exact deployment name from the Deployments page. The deployment name is what you created when you deployed the model — it is not the model name itself.
// WRONG: using the model name
ChatClient chatClient = client.GetChatClient("gpt-4o");
// CORRECT: using your deployment name
ChatClient chatClient = client.GetChatClient("my-gpt4o-deployment");
You can also list deployments programmatically:
az cognitiveservices account deployment list \
--name your-openai-resource \
--resource-group your-rg \
--output table
Prevention Checklist
- Never hardcode keys. Use
dotnet user-secretslocally and Azure Key Vault or managed identity in production. - Use managed identity in production. It eliminates key rotation headaches entirely.
- Verify endpoint and deployment name together. They are a pair — both must belong to the same resource.
- Assign the least-privilege RBAC role.
Cognitive Services OpenAI Useris sufficient for inference. Do not grantContributorunless the identity needs to manage deployments. - Log the endpoint (not the key) on startup. This makes it easy to spot misconfiguration without leaking secrets.
- Set up health checks. A lightweight completion call during startup catches auth problems before the first real request.
Further Reading
- Azure OpenAI API Reference
- Azure.AI.OpenAI on NuGet
- RBAC: Cognitive Services OpenAI User Role
- Azure OpenAI questions on StackOverflow
- Azure SDK for .NET — OpenAI 401 Issues