Azure Authentication — Complete Reference¶
The core concept
Every call to an Azure service needs to answer one question: who are you? Azure has multiple ways to answer that question depending on where your code is running and what you're connecting to.
The four authentication methods
1. Access Keys / Connection Strings
The oldest, simplest method. Every storage account, Service Bus, etc. has keys generated by Azure. You use them directly.
// Connection string
var client = new BlobServiceClient("DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;");
// Or just the key
var client = new BlobServiceClient(
new Uri("https://account.blob.core.windows.net"),
new StorageSharedKeyCredential("accountName", "accountKey")
);
How it works: The key is a shared secret. Anyone who has it can do anything the key permits. No identity involved — just a password.
Pros: Simple, works everywhere, no setup.
Cons: Credential can leak. Needs rotation. If leaked, full access until rotated. Not auditable — Azure can't tell which app used the key.
When to use: Local development quick tests, or when nothing else is available. Never in production if avoidable.
2. az login (Azure CLI credential)
You run az login on your machine. Azure authenticates you as a human user and stores a token at ~/.azure/. DefaultAzureCredential picks this up automatically.
az login
# browser opens, you sign in
# token stored at ~/.azure/
// Your code — nothing special needed
var client = new BlobServiceClient(
new Uri("https://account.blob.core.windows.net"),
new DefaultAzureCredential() // picks up az login session automatically
);
How it works: Your human user account gets a token from Entra ID. Azure checks your RBAC role assignments — if you have Storage Blob Data Contributor on the storage account, access is granted.
Pros: No credentials in code. Uses your actual identity. Perfect for local development.
Cons: Only works on your machine. Tokens expire — az login occasionally needs to be re-run. Not suitable for production.
When to use: Local development always. Never in production.
3. Managed Identity
An identity automatically created and managed by Azure for a resource — VM, Function App, App Service, Container App. No credentials exist anywhere. Azure handles the token exchange internally.
Two types:
System Assigned — tied to the resource lifecycle. Created when you assign it, deleted when the resource is deleted. One identity per resource.
az functionapp identity assign --name my-function --resource-group my-rg
# Azure creates an identity, outputs principalId
User Assigned — independent identity you create separately and attach to multiple resources. Survives resource deletion. Useful for Swarm VMs where multiple VMs need the same identity.
# Create once
az identity create --name my-identity --resource-group my-rg
# Attach to multiple VMs
az vm identity assign --name vm1 --identities my-identity
az vm identity assign --name vm2 --identities my-identity
// Code is identical regardless of which type
var client = new BlobServiceClient(
new Uri("https://account.blob.core.windows.net"),
new DefaultAzureCredential() // on Azure VM/Function, picks up Managed Identity
);
How it works: Azure exposes an internal metadata endpoint (http://169.254.169.254) inside every VM and Function App. DefaultAzureCredential calls this endpoint to get a token for the resource's identity. No credentials needed — Azure vouches for the resource.
Pros: No credentials anywhere. Nothing to rotate. Most secure option. Auditable — Azure knows exactly which resource made the call.
Cons: Only works on Azure infrastructure. Local development needs a different credential (az login). Requires role assignments to be set up explicitly.
When to use: Production on Azure always. Your VMs, Function Apps, App Services — always use Managed Identity in production.
Role assignments needed — this is mandatory. Managed Identity alone doesn't grant access to anything. You must explicitly assign RBAC roles:
az role assignment create \
--assignee <principalId> \
--role "Storage Blob Data Contributor" \
--scope "/subscriptions/.../storageAccounts/averblobstore"
4. Service Principal
An app identity in Entra ID — not a human, not tied to a resource. You create it manually, get credentials, and use them anywhere. Works on any infrastructure — Azure VMs, Hetzner, DigitalOcean, your own VPS, CI/CD pipelines.
az ad sp create-for-rbac --name "my-app"
# outputs: appId, password, tenant
# Set as environment variables wherever your app runs
AZURE_CLIENT_ID=appId
AZURE_CLIENT_SECRET=password
AZURE_TENANT_ID=tenant
// Code is identical — DefaultAzureCredential picks up env vars automatically
var client = new BlobServiceClient(
new Uri("https://account.blob.core.windows.net"),
new DefaultAzureCredential()
);
How it works: DefaultAzureCredential finds the three env vars, uses them to request a token from Entra ID as the Service Principal identity. Azure checks RBAC role assignments for that identity.
Pros: Works anywhere, not tied to Azure infrastructure. Good for CI/CD, third-party VMs, cross-cloud scenarios.
Cons: Has a secret (AZURE_CLIENT_SECRET) that can leak and needs rotation. Less secure than Managed Identity. You manage the credential lifecycle.
When to use: Non-Azure infrastructure that needs to access Azure services. CI/CD pipelines. Third-party VM running your Swarm that needs Blob Storage access.
DefaultAzureCredential — the unifying abstraction
All four methods above (except raw connection strings) are unified under DefaultAzureCredential. It tries each credential type in order, stops at first success:
1. EnvironmentCredential → AZURE_CLIENT_ID/SECRET/TENANT env vars (Service Principal)
2. WorkloadIdentityCredential → Kubernetes workload identity
3. ManagedIdentityCredential → Azure VM/Function Managed Identity
4. SharedTokenCacheCredential → shared token cache
5. VisualStudioCredential → Visual Studio login
6. VisualStudioCodeCredential → VS Code Azure extension
7. AzureCliCredential → az login session ← your local dev
8. AzurePowerShellCredential → Azure PowerShell
9. AzureDeveloperCliCredential → azd login
This is why the same code works everywhere:
Local machine → no env vars, no Managed Identity → falls through to AzureCliCredential
Azure VM → Managed Identity available → stops at ManagedIdentityCredential
Third-party VM → AZURE_ env vars set → stops at EnvironmentCredential
CI/CD pipeline → AZURE_ env vars set → stops at EnvironmentCredential
One line of code, four environments, four different auth mechanisms, zero branching.
Critical gotcha: EnvironmentCredential runs before ManagedIdentityCredential. If you have AZURE_ env vars set locally from a previous project, they'll take priority over your az login session. Always check printenv | grep AZURE if auth behaves unexpectedly locally.
RBAC — the permission model that underlies everything
Authentication (who are you) is separate from authorisation (what can you do). Every identity — user, Managed Identity, Service Principal — needs explicit RBAC role assignments to access resources.
Three things in every role assignment:
WHO → principalId (user, Managed Identity, Service Principal)
WHAT → Role (Storage Blob Data Contributor, Key Vault Secrets User, etc.)
WHERE → scope (subscription, resource group, or specific resource)
Roles you'll use most:
Storage Blob Data Contributor → read/write blobs
Storage Queue Data Contributor → read/write queues (needed for blob trigger checkpointing)
Storage Table Data Contributor → read/write tables (needed for blob trigger state)
Key Vault Secrets User → read secrets
Key Vault Secrets Officer → read/write secrets (for your admin account)
Control plane vs data plane — the Key Vault gotcha:
Key Vault has two planes:
Control plane → manage the vault itself (create, delete, configure)
→ Owner/Contributor role at subscription covers this
Data plane → read/write actual secrets
→ requires explicit Key Vault Secrets User role on the vault itself
→ Owner at subscription does NOT automatically grant this
This is why you got RBAC errors on Key Vault even with Owner inherited — Owner covers the control plane, not the data plane. Always assign data plane roles explicitly on the resource.
The three environments mapped out
Local development
→ az login on your machine
→ Your user account has roles assigned
→ DefaultAzureCredential → AzureCliCredential
→ No credentials in code
Production on Azure (VMs, Functions, App Service)
→ Managed Identity assigned to the resource
→ Identity has roles assigned
→ DefaultAzureCredential → ManagedIdentityCredential
→ No credentials anywhere
Production on non-Azure (Hetzner, DigitalOcean, your VPS)
→ Service Principal created
→ AZURE_CLIENT_ID/SECRET/TENANT in env vars
→ DefaultAzureCredential → EnvironmentCredential
→ Three env vars only, everything else from Key Vault
Connection strings vs Managed Identity vs Key Vault references
Raw connection string in app settings
→ credential visible in portal
→ can leak
→ needs rotation
→ avoid in production
Connection string in Key Vault, referenced in app settings
→ @Microsoft.KeyVault(VaultName=peppol-vault;SecretName=BlobStorageConnection)
→ credential secured, never visible
→ still exists and needs rotation
→ good for third-party credentials you have no choice about
Managed Identity, no connection string
→ no credential anywhere
→ nothing to rotate
→ most secure
→ only works for Azure services that support it
Rule of thumb:
Azure service to Azure service → Managed Identity always
Third-party API key → Key Vault reference
Local development → az login, never connection strings in code
The bootstrapping problem
Key Vault solves the "credentials in code" problem. But to access Key Vault you need credentials. This is the bootstrapping problem.
Resolution:
On Azure (VM/Function)
→ Managed Identity opens Key Vault
→ No credentials at all
→ Problem fully solved
On non-Azure (third-party VM)
→ Three env vars (Service Principal) bootstrap Key Vault
→ Everything else lives in Key Vault
→ Reduced from N credentials scattered everywhere to 3 env vars
Local development
→ az login bootstraps everything
→ No env vars needed
The three env vars for Service Principal are the irreducible minimum when not on Azure infrastructure. Everything downstream of Key Vault is secured. That's the best you can do outside Azure.