Storage SAS — user delegation, service and account SAS, expiration policy and pitfalls

Which shared access signature to use and why it fails — user delegation SAS signed with an Entra-issued key (7-day limit, Delegator roles, user-bound SAS from service version 2025-07-05, cross-tenant delegation off by default), service and account SAS signed with the account key, stored access policies for revocation, the account's SAS expiration policy with Log or Block, clock skew, and which SAS still works when Shared Key is off.

markdownreferencev1CET4-R3F1stage: buildtrust: officialservice: storageinterface: sdkinterface: cliuser delegation SASuser delegation keygetUserDelegationKeygenerateUserDelegationSasUrlgenerateUserDelegationKey actionStorage Blob Delegatorservice SASaccount SASstored access policyrevoke SASsasPolicysasExpirationPeriodexpirationAction BlockSasExpiryStatusPolicy violatedrequireUserBoundUserDelegationSasdelegatedUserObjectIduser-bound user delegation SASallowCrossTenantDelegationSasdelegatedUserTenantIdSAS clock skew 15 minutesSAS start timeaz storage blob generate-sas --as-userSAS seven days

Created 21 Oct 2026 · Modified 23 Oct 2026 · 1 version

Storage SAS — user delegation, service and account SAS

Use a user delegation SAS whenever a SAS is needed. It's signed with a key that Entra ID issues to the caller, so it works with Shared Key off, it carries at most the caller's own permissions, and it never touches the account key. Service and account SAS are signed with the account key: whoever holds the key can mint them, and the only revocation is rotating the key (or deleting a stored access policy).

The three kinds

KindSigned withServicesRevoke by
User delegation SASUser delegation key from Get User Delegation Key, called with an Entra tokenBlob and Data Lake; the SAS overview and the Queue and File SDKs add Queue, Table and FilesKey expiry (≤ 7 days), or az storage account revoke-delegation-keys -n <acct> -g <rg> (revokes every key)
Service SASAccount keyOne serviceRotate the key, or delete its stored access policy
Account SASAccount keyOne or more services (ss), resource types (srt)Rotate the key
  • To get the key, the caller needs a role with …/generateUserDelegationKey/action: Storage Blob Delegator (or Queue, File, Table Delegator), or Storage Blob Data Contributor/Owner which include it. The SAS then grants only the permissions both in the SAS and in the caller's data roles.
  • The key's start and expiry must both be within 7 days of now, and a user delegation SAS can't outlive 7 days whatever the account's expiration policy says.
  • Stored access policies work only with a service SAS. User delegation and account SAS must be ad hoc.

With Shared Key off (allowSharedKeyAccess: false), service and account SAS fail with KeyBasedAuthenticationNotPermitted; a user delegation SAS keeps working. Microsoft's shared-key page labels user delegation SAS "Blob Storage only" in the same place, which contradicts its SAS overview: verify a Queue or Files user delegation SAS against your account before depending on it.

User-bound user delegation SAS (2025-07-05 and later)

A SAS can be bound to one user: set delegatedUserObjectId when signing, and the SAS works only alongside an Entra token issued to that object ID. The account can demand it: sasPolicy.requireUserBoundUserDelegationSas: true, with requireUserBoundUserDelegationSasAction None, Log or Block (2026-06-01 API). A user delegation key for another tenant (delegatedUserTenantId) works only if allowCrossTenantDelegationSas is true; its default is false.

SAS expiration policy

sasPolicy.sasExpirationPeriod (format DD.HH:MM:SS) sets a recommended maximum validity for service and account SAS:

  • expirationAction: Log (the default) allows out-of-policy SAS and writes SasExpiryStatus in resource logs (StorageBlobLogs | where SasExpiryStatus startswith "Policy violated"). Block refuses them.
  • With a policy in effect, every SAS must include a signed start (st); validity is se − st.
  • It doesn't apply to user delegation SAS through the HDFS endpoint, or to service SAS that use a stored access policy.
  • CLI: az storage account update -n <acct> -g <rg> --sas-expiration-period 1.00:00:00 --sas-expiration-action Block. Built-in policy: Storage accounts should have shared access signature (SAS) policies configured.

Pitfalls

  • Clock skew. Up to 15 minutes either way. Don't set st to now: omit it (valid immediately) or set it 15 minutes in the past; leave margin on se. With an expiration policy, st is required, so back-date it.
  • Permissions per operation. Overwriting a blob needs write and delete; listing needs l; an account-level call (list containers) needs an account SAS, not a service SAS.
  • spr. https only is recommended; HTTP-only isn't a valid value. sip takes IPv4 only, and a SAS IP restriction never grants access the firewall denies.
  • A SAS is a bearer secret. Don't log the URL; hand it out with the shortest life that works.
  • Generate it with the SDK or CLI. A hand-built token fails with SAS field 'sv' is not well formed. and similar.

CLI, user delegation SAS valid for one hour (--as-user requires --auth-mode login and --expiry):

az storage blob generate-sas --account-name <acct> --container-name <c> --name <blob> \
  --permissions r --expiry <yyyy-mm-ddThh:mmZ> --https-only --as-user --auth-mode login --full-uri

TypeScript: guides/storage/access-blobs-from-typescript.md §4. Errors: reference/storage/sas-and-key-errors.md.

Read this document as markdown — the same bytes an agent receives.