Cloud & infrastructure

Azure Storage SAS Tokens: User Delegation SAS vs Account Keys

Share Azure blobs through expiring links without handing out account keys. Compare the three SAS types, create a user delegation SAS with the Azure CLI and revoke it.

By EpiFive Editorial TeamReviewed/updated 12 min readHow we check articles
On this page

A shared access signature (SAS) is a token you append to a storage URL so a client can read or write specific data for a limited time. For blob links that should expire, create a user delegation SAS: it is signed with Microsoft Entra credentials rather than the storage account key, which is why Microsoft recommends it over the other two SAS types. The sections below show how each type works, how to create and revoke a user delegation SAS with the Azure CLI, and how to shut off account keys entirely.

Who this is for and what you will have at the end

This guide is for developers and administrators who need to hand out time-limited access to Azure Blob Storage, for example a download link for a customer, an upload target for a web app, or a one-off file transfer to a partner. You do not need to be an Azure expert, but you should be comfortable with a terminal and know what a storage account and container are.

By the end you will be able to:

  • Explain the difference between user delegation, service and account SAS tokens.
  • Create a read-only, expiring link to a single blob with the Azure CLI.
  • Revoke user delegation SAS tokens when one leaks.
  • Disallow account key authorization so that only Microsoft Entra-based access works.

If you are still choosing how a storage account replicates data, see Azure storage account redundancy: LRS, ZRS and GRS. For a similar keyless pattern on another service, see Azure OpenAI keyless access with managed identity.

How a SAS works

A SAS is a string of query parameters appended to the URI of a storage resource. One of those parameters, the signature, is computed from the other parameters and signed with a key. When a request arrives, Azure Storage checks the parameters and the signature. If the signature is valid, the request is authorized; otherwise it is declined with error code 403 (Forbidden).

The token is generated on the client side, for example by the Azure CLI or an SDK. Azure Storage does not track tokens in any way, you can create an unlimited number of them, and there is no API that lists the SAS tokens issued for an account.

Two practical consequences follow:

  • Anyone who holds the token can use it, within the permissions and time window it encodes.
  • Microsoft notes that generating a SAS cannot be audited. Anyone with the account key, or with an Azure role that lets them generate a SAS, can do so without the storage account owner knowing. Restrict who has those permissions.

The ? that separates a URL from its query string is not part of the SAS token. When you build a URL by hand, add the ? yourself.

The three SAS types

Azure Storage supports three kinds of SAS. The difference that matters most is what signs the token.

TypeSigned withScopeStored access policy
User delegation SASUser delegation key (Microsoft Entra credentials)Blob Storage (including Data Lake Storage), Queue, Table or Azure FilesNot supported
Service SASStorage account keyOne service: Blob, Queue, Table or Azure FilesSupported
Account SASStorage account keyOne or more storage services, including service-level operationsNot supported

A user delegation SAS and an account SAS must be ad hoc, meaning the start time, expiry time and permissions are all written into the token. A service SAS can instead reference a stored access policy defined on a container, queue, table or file share, and inherit its constraints from the policy.

Why Microsoft recommends the user delegation SAS

Microsoft's documentation states that when you need a SAS, a user delegation SAS provides superior security because it is secured with Microsoft Entra credentials. You never need to keep the account key in your code or configuration. The key that signs the SAS is derived from an identity you can control with Azure RBAC, and you can revoke it without rotating the account keys that other workloads may depend on.

The trade-offs to know about:

  • Lifetime is capped at 7 days (explained below).
  • The identity that creates it needs a role that includes the generateUserDelegationKey action.
  • No stored access policies, so constraints are fixed inside the token.

Prerequisites

You need:

  • A storage account with a container and at least one blob.
  • Azure CLI version 2.0.78 or later. Check with az --version.
  • A Microsoft Entra account that can sign in to the CLI.
  • An Azure role for that account that includes Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey, assigned at the storage account, resource group or subscription scope.

Microsoft's example uses the built-in Storage Blob Data Contributor role, which includes that action. Assign it at the storage account level:

az role assignment create \
    --role "Storage Blob Data Contributor" \
    --assignee [email protected] \
    --scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>"

If you cannot assign roles yourself, ask the account owner or an administrator. Sign in before you continue:

az login

Create a user delegation SAS for a blob

Use az storage blob generate-sas. Two parameters are required for a user delegation SAS: --auth-mode login so that requests are authorized with your Microsoft Entra credentials, and --as-user so that the token returned is a user delegation SAS.

az storage blob generate-sas \
    --account-name <storage-account> \
    --container-name reports \
    --name q3-summary.pdf \
    --permissions r \
    --expiry 2026-11-05T00:00:00Z \
    --auth-mode login \
    --as-user \
    --full-uri

What each part does:

  • --permissions r grants read only. For a blob, the supported user delegation permissions are Add, Create, Delete, Read and Write, which you can combine. The documentation example uses acdrw.
  • --expiry is when the token stops working. The start and expiry you give are also used as the start and expiry of the user delegation key.
  • --full-uri returns the blob URL with the token already appended, so you can share the output directly.

The result is a URL of the form https://<storage-account>.blob.core.windows.net/reports/q3-summary.pdf?se=...&sp=r&sv=...&sr=b&skoid=...&sktid=...&sig=.... Without --full-uri you get only the token, and you must add ? before it.

Keep expiry within 7 days

The maximum interval over which a user delegation key is valid is 7 days from the start date. The SAS is invalid once the key expires, so a SAS with an expiry later than 7 days is still only valid for 7 days. Choose an expiry inside that window, and shorter if the task allows it. Short expiry also limits what a leaked link can cost you, since the account is billed for any usage, including usage through a SAS.

Create a container-level SAS

To share a whole container, use az storage container generate-sas. Supported user delegation permissions on a container are Add, Create, Delete, List, Read and Write.

az storage container generate-sas \
    --account-name <storage-account> \
    --name reports \
    --permissions lr \
    --expiry 2026-11-05T00:00:00Z \
    --auth-mode login \
    --as-user

Prefer a blob-level token with read-only permission when the recipient needs a single file. Least privilege limits the damage if a token leaks.

Clock skew and start time

If you set the SAS start time to the current time, requests can fail intermittently for the first few minutes because machines disagree slightly about the time. Microsoft's guidance is to set the start time at least 15 minutes in the past or leave it out, which makes the token valid immediately. Allow for up to 15 minutes of skew at the expiry end too. If you use AzCopy, date and time values must include seconds, in the format +%Y-%m-%dT%H:%M:%SZ.

Open the full URI in a browser or fetch it from a terminal:

curl -I "https://<storage-account>.blob.core.windows.net/reports/q3-summary.pdf?<sas-token>"

A 200 OK response means the token works. If you try a permission the token does not grant, such as a write with a read-only token, Azure Storage returns a 403.

Revoke a user delegation SAS

You cannot list or delete an individual SAS, because Azure Storage does not track them. For user delegation tokens, the lever is the user delegation key. This command revokes all user delegation keys for the storage account and invalidates every SAS signed with them:

az storage account revoke-delegation-keys \
    --name <storage-account> \
    --resource-group <resource-group>

Two cautions from the documentation. First, the revocation applies to all user delegation keys on the account, so every outstanding user delegation SAS stops working, not only the leaked one. Second, Azure Storage caches both the user delegation key and Azure role assignments, so there can be a delay between running the command and the token becoming invalid.

Service SAS and account SAS: when keys are involved

If you sign a SAS with the account key you create a service SAS or an account SAS. Anyone who can obtain the key, or who holds the Microsoft.Storage/storageAccounts/listkeys/action permission, can mint tokens. Revoking a leaked key-signed token without a stored access policy means rotating the account key, which affects every other client using that key.

If you must use a service SAS:

  • Attach it to a stored access policy on the container so that you can revoke it by changing or deleting the policy instead of rotating keys. There is a limit of five stored access policies per container.
  • Use near-term expiry on any ad hoc service or account SAS.
  • Configure a SAS expiration policy on the storage account. It sets a recommended maximum validity for service and account SAS tokens. Users who exceed it see a warning, and an entry is written to the Azure Storage logs if logging with Azure Monitor is enabled. It does not block creation.

Disallow account keys

The most effective way to keep key-signed tokens out of your environment is to disable Shared Key authorization on the account. Microsoft documents the effect on each SAS type:

SAS typeBehavior when AllowSharedKeyAccess is false
User delegation SAS (Blob Storage only)Request is permitted
Service SASRequest is denied for all Azure Storage services
Account SASRequest is denied for all Azure Storage services

Before you flip the setting, check what depends on keys. Some Azure services and tools authenticate to storage with Shared Key, and they stop working when it is disallowed. Azure Files is the notable case: by default the Azure portal uses Shared Key to access file shares, so file share access in the portal fails unless you have the proper RBAC assignments. Azure Cloud Shell stores its files in an Azure file share, which becomes inaccessible if the account disallows Shared Key. Also note that Microsoft Entra Conditional Access policies can protect a storage account only if Shared Key authorization is disallowed.

To find out who is still using keys or SAS, create a diagnostic setting that sends storage logs to a Log Analytics workspace and run this query, which lists the ten callers sending the most requests authorized with an account key or a SAS in the last seven days:

StorageBlobLogs
| where AuthenticationType in ("AccountKey", "SAS") and TimeGenerated > ago(7d)
| summarize count() by CallerIpAddress, UserAgentHeader, AccountName
| top 10 by count_ desc

Note that logs report all SAS types together under SAS, so a user delegation SAS also shows up here.

When clients are migrated, disallow Shared Key access:

az storage account update \
    --name <storage-account> \
    --resource-group <resource-group> \
    --allow-shared-key-access false

This needs Azure CLI 2.20.0 or later. In the portal, open the storage account, go to Configuration under Settings, and set Allow storage account key access to Disabled. Verify the change:

az storage account show \
    --name <storage-account> \
    --resource-group <resource-group> \
    --query "allowSharedKeyAccess"

The command returns false when Shared Key authorization is disallowed. Afterward, a request that uses Shared Key fails with a 403 (Forbidden) and an error saying key-based authorization is not permitted.

To keep it that way, assign the built-in Azure Policy Storage accounts should prevent shared key access, first with the Audit effect to find non-compliant accounts, then with Deny. Policy changes can take up to 30 minutes to apply.

Troubleshooting

SymptomLikely causeFix
403 Forbidden on a fresh tokenStart time set to now and clock skewRemove the start time or set it at least 15 minutes in the past
403 after a few daysUser delegation key expired after 7 daysGenerate a new token with a shorter, in-window expiry
Cannot create the SASSigning identity lacks the generateUserDelegationKey action, or you omitted --auth-mode login or --as-userAssign Storage Blob Data Contributor or another role with that action, and include both parameters
Link works for the container but not nested blobsToken created for the wrong resource typeCheck the sr parameter: c for container, b for blob
Service SAS suddenly deniedShared Key access disallowed on the accountMove to a user delegation SAS or Microsoft Entra authorization
Token still works after revocationCached keys and role assignmentsWait and retest; the documentation warns of a delay
Portal cannot browse file shares after disabling keysPortal uses Shared Key for Azure Files by defaultAuthorize with Microsoft Entra in the portal and assign the needed RBAC roles

Checklist

  • Use a user delegation SAS wherever the data is in Blob Storage.
  • Grant the fewest permissions on the narrowest resource, usually read on one blob.
  • Keep expiry short and always inside 7 days.
  • Always create and share SAS links over HTTPS.
  • Validate anything that clients write using a SAS before your application trusts it.
  • Know how you would revoke: az storage account revoke-delegation-keys for user delegation tokens, a stored access policy or key rotation for service tokens.
  • Restrict who holds roles that can generate keys or SAS tokens, since generation cannot be audited.
  • Monitor authorization failures with Azure Monitor and storage logs.
  • Move to --allow-shared-key-access false once nothing depends on keys.
  • If a container's contents are meant to be public, public read access may be simpler than distributing SAS tokens.

References

Questions people ask

What is the difference between a user delegation SAS and a service SAS?

A user delegation SAS is signed with a key obtained through Microsoft Entra credentials, so no account key is involved. A service SAS is signed with the storage account key. Microsoft recommends the user delegation SAS wherever you need a SAS.

How long can a user delegation SAS be valid?

The user delegation key that signs it is valid for at most 7 days from its start time. A SAS with a later expiry is still only valid until the key expires, so plan on an expiry within 7 days of the start time.

How do I revoke a user delegation SAS?

Run az storage account revoke-delegation-keys for the storage account. This revokes all user delegation keys for the account, which invalidates every SAS signed with them. Azure Storage caches keys and role assignments, so the SAS may keep working briefly.

Does a user delegation SAS still work if I disable Shared Key access?

Yes for Blob Storage. A user delegation SAS is authorized with Microsoft Entra ID, so requests are permitted when AllowSharedKeyAccess is false. Service SAS and account SAS requests are denied.

Azure StorageSASManaged identityBlob Storage
  1. Azure Key Vault RBAC vs Access Policies: Migrate and Assign Roles

    Compare Key Vault access policies with Azure RBAC, map policy templates to built-in roles, switch a vault to the RBAC permission model safely, and assign least-privilege roles.

  2. Azure Storage Redundancy: LRS vs ZRS vs GRS vs GZRS Explained

    Compare Azure Storage redundancy options by durability, availability, failure scenarios and cost order, and learn how to change a storage account's redundancy safely.

  3. Azure Policy Tag Enforcement: Require, Inherit and Remediate Tags

    Enforce CostCenter and Owner tags with built-in Azure Policy definitions: deny untagged resource groups, inherit tags onto resources, and remediate existing resources with managed identities.

  4. Fix Azure private endpoint DNS from on-premises with DNS Private Resolver

    Stop private endpoints resolving to public IP addresses from on-premises and VPN clients: link the privatelink zone, add a DNS Private Resolver inbound endpoint and forward the right zones.

  5. AWS EC2 Pricing Explained: On-Demand, Savings Plans, Reserved and Spot

    Compare the EC2 purchasing options in USD terms: On-Demand, Savings Plans, Reserved Instances and Spot. Learn when each fits and how to estimate cost with the AWS Pricing Calculator.

  6. Azure Reservations vs Savings Plan for Compute: Which Saves More

    Compare Azure reserved instances with a compute savings plan for steady workloads, including discounts, flexibility, exchange and refund rules, and how the two apply together.