---
cuppy_hub: azure
cuppy_path: reference/storage/sas.md
cuppy_section: docs
cuppy_doc: CET4-R3F1
cuppy_doc_uuid: 1c3ad14b-4bf5-4ee7-b088-ba279a9005bd
cuppy_permalink: https://cuppy.io/azure/d/CET4-R3F1
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/azure/docs/reference/storage/sas
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 4938fd5896ae8b72984d6712385692aa23f1b60a2b88dd3a4ad19bae1b45b01b
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# 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

| Kind | Signed with | Services | Revoke by |
|---|---|---|---|
| **User delegation SAS** | User delegation key from `Get User Delegation Key`, called with an Entra token | Blob and Data Lake; the SAS overview and the Queue and File SDKs add Queue, Table and Files | Key expiry (≤ 7 days), or `az storage account revoke-delegation-keys -n <acct> -g <rg>` (revokes every key) |
| **Service SAS** | Account key | One service | Rotate the key, or delete its stored access policy |
| **Account SAS** | Account key | One 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`):

```bash
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`.


---
<!-- 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 -->
