---
cuppy_hub: azure
cuppy_path: patterns/app-to-storage-with-managed-identity.md
cuppy_section: docs
cuppy_doc: 2GNJ-V717
cuppy_doc_uuid: 4133b354-1b12-4f70-8cd5-f4b17302b3dc
cuppy_permalink: https://cuppy.io/azure/d/2GNJ-V717
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/azure/docs/patterns/app-to-storage-with-managed-identity
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: f2690469e06e6e979b111c583713624d0be88406f92960e7ce402d81147c7b69
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# App to Blob Storage with a managed identity

**App side:** the app runs as a managed identity and asks for a token for `https://storage.azure.com`. **Storage side:** the account's network lets the app in, then a data role on the account or container grants the operation. Every failure below is one of those, and the error code tells you which.

## Known-good

- A user-assigned identity `id-orders`, attached to the app; its client ID in the app setting `APP_IDENTITY_CLIENT_ID`.
- **Storage Blob Data Contributor** for the identity's `principalId` on the container (or account), `principalType: ServicePrincipal`, `guid()` name. Reader if it only reads.
- Account: `allowSharedKeyAccess: false`, `minimumTlsVersion: 'TLS1_2'`, `allowBlobPublicAccess: false` (`guides/storage/create-secure-storage-account.md`).
- Network, for an app **in the same region**: VNet integration into a subnet that has the `Microsoft.Storage` service endpoint and a **VNet rule** on the account; or `publicNetworkAccess: Disabled` with a **private endpoint** for `blob` (and `dfs` for Data Lake) and the `privatelink.blob.core.windows.net` zone linked to the app's VNet.
- Code: `new BlobServiceClient("https://<acct>.blob.core.windows.net", new ManagedIdentityCredential({ clientId: process.env.APP_IDENTITY_CLIENT_ID }))`, one client per process (`guides/storage/access-blobs-from-typescript.md`).

Setting up the identity: `guides/managed-identity/use-managed-identity.md`. Assigning the role: `guides/rbac/assign-roles.md`.

## Known-bad

| Configuration | Symptom |
|---|---|
| Identity holds Owner or Contributor on the account, no data role | 403 `AuthorizationPermissionMismatch` `This request is not authorized to perform this operation using this permission.` |
| Role assigned a minute ago | Same 403 for 10–30 minutes, then it works |
| Role on a **group** containing the identity | Same 403 for hours: managed identity tokens are cached (about 24 h) with the group memberships they were issued with |
| App still uses a connection string after Shared Key was turned off | 403 `KeyBasedAuthenticationNotPermitted` `Key based authentication is not permitted on this storage account.` |
| Firewall `defaultAction: Deny` with the app's **outbound IPs** in `ipRules`, app in the same region | 403 `AuthorizationFailure` `This request is not authorized to perform this operation.`: same-region traffic arrives on private addresses, so IP rules never match |
| Relying on `bypass: AzureServices` for App Service or Functions | Same `AuthorizationFailure`: they aren't trusted services |
| Private endpoint created, DNS zone not linked to the app's VNet | The name resolves to the public IP: `AuthorizationFailure` if public access is denied, or a timeout |
| Data Lake account with only a `blob` private endpoint | Directory and ACL operations through `dfs` fail |
| Two user-assigned identities, `DefaultAzureCredential` with no client ID | Token for the wrong identity or none: 403, or `ManagedIdentityCredential` errors |
| Custom HTTP code requests a token for another audience (for example `https://management.azure.com`) | 401 `Server failed to authenticate the request. Please refer to the information in the www-authenticate header.` |

## Which side is wrong

- **No token** (`ManagedIdentityCredential…`, IMDS or `IDENTITY_ENDPOINT` errors) → the app: identity attached, right client ID (`reference/managed-identity/errors.md`).
- **401** → the token's audience. Use the SDK; the scope is `https://storage.azure.com/.default`.
- **403 `AuthorizationFailure`** → the storage account's network: firewall, public network access, private endpoint DNS (`reference/storage/network-and-firewall.md`).
- **403 `AuthorizationPermissionMismatch`** → the role: missing, on Owner/Contributor only, on a group, not propagated, or (Data Lake, no role) a missing ACL Execute on a parent.
- **403 `KeyBasedAuthenticationNotPermitted`** → the app's configuration still uses a key or a non-user-delegation SAS.

`az storage account show -n <acct> --query "{public:publicNetworkAccess, firewall:networkRuleSet, sharedKey:allowSharedKeyAccess}"` answers the storage-side questions in one call; `az role assignment list --assignee <principal-id> --all -o table` answers the role question.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 107 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/azure/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
