Skip to content

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.