SAS Tokens Explained: Shared Access Signatures in Azure
A SAS token is a signed URL string that grants time-limited, permission-scoped access to a specific Azure Storage resource. Instead of handing out your storage account key, you create a SAS token that can read one blob, write to one container, or manage one queue — and only for the next hour, or day, or week. When the time runs out, the token stops working automatically.
Why SAS tokens exist
Your storage account has two master keys — think of them as root passwords. Anyone who has a key can read, write, delete, or reconfigure anything in the account. You would never give a master key to a client application, a third-party contractor, or a temporary user.
SAS tokens solve this by letting you delegate specific permissions for a specific time window. A file download link that expires in 24 hours. A write-only URL for a CI pipeline to upload artifacts. A read-only token for a contractor to access a specific container. None of these require sharing your account key.
Types of SAS tokens
| Type | Scope | Signed with | Revocable |
|---|---|---|---|
| Service SAS | One service (blob, file, queue, or table) | Account key or stored access policy | Only if using stored access policy |
| Account SAS | Multiple services in one account | Account key | Only by rotating account key |
| User delegation SAS | Blobs only | Azure AD credentials (via Managed Identity or user login) | Yes — by revoking the delegation key |
User delegation SAS is the most secure type because it does not involve account keys at all. It requires Azure AD authentication and can be revoked by revoking the delegation key. Use this when possible.
Generating SAS tokens with Azure CLI
Here are the most common scenarios you’ll encounter:
# Generate a SAS token for a single blob (read-only, expires in 1 hour)
EXPIRY=$(date -u -d "+1 hour" '+%Y-%m-%dT%H:%MZ')
az storage blob generate-sas \
--account-name mystorageaccount123 \
--container-name assets \
--name images/logo.png \
--permissions r \
--expiry "$EXPIRY" \
--auth-mode login \
--as-user \
--output tsvThe —as-user and —auth-mode login flags generate a user delegation SAS (signed with Azure AD, not account keys). The output is the query string portion of the SAS token.
# Build the full URL from the token
ACCOUNT="mystorageaccount123"
CONTAINER="assets"
BLOB="images/logo.png"
TOKEN=$(az storage blob generate-sas \
--account-name $ACCOUNT \
--container-name $CONTAINER \
--name "$BLOB" \
--permissions r \
--expiry "$EXPIRY" \
--auth-mode login \
--as-user \
--output tsv)
echo "https://$ACCOUNT.blob.core.windows.net/$CONTAINER/$BLOB?$TOKEN"# Generate a SAS for an entire container (read + list, 7 days)
EXPIRY=$(date -u -d "+7 days" '+%Y-%m-%dT%H:%MZ')
az storage container generate-sas \
--account-name mystorageaccount123 \
--name assets \
--permissions rl \
--expiry "$EXPIRY" \
--auth-mode login \
--as-user \
--output tsvThe —permissions flag takes a combination of characters: r (read), w (write), d (delete), l (list), a (add), c (create). For blobs, rl gives read and list access.
Stored access policies for revocable SAS tokens
An ad-hoc SAS token cannot be revoked before it expires — once issued, it’s valid until the expiry time or until you rotate the account key (which is disruptive). Stored access policies solve this by attaching the SAS permissions to a named policy on the container, which you can delete at any time to revoke all tokens linked to that policy.
# Create a stored access policy on a container
az storage container policy create \
--account-name mystorageaccount123 \
--container-name assets \
--name "read-only-30days" \
--permissions rl \
--expiry "2026-04-19T00:00:00Z" \
--auth-mode login
# Generate a SAS token backed by the stored policy
az storage blob generate-sas \
--account-name mystorageaccount123 \
--container-name assets \
--name images/logo.png \
--policy-name "read-only-30days" \
--output tsv
# Revoke all tokens under this policy by deleting the policy
az storage container policy delete \
--account-name mystorageaccount123 \
--container-name assets \
--name "read-only-30days" \
--auth-mode loginOnce you delete the policy, any SAS token that referenced it immediately stops working — even if the expiry date hasn’t passed yet. This is the only reliable way to revoke a service SAS without rotating account keys.
SAS tokens in real application patterns
The most common pattern in web applications is the pre-signed URL pattern: the client requests a temporary upload URL from your backend, and then uploads directly to Azure Storage without routing the file through your servers.
- Client sends a request to your backend API: “I need to upload a file.”
- Backend generates a SAS token for a specific blob path with write permission and a 15-minute expiry.
- Backend returns the pre-signed URL to the client.
- Client uploads the file directly to Azure Storage using the URL — no backend involvement.
- After 15 minutes, the URL is useless.
This pattern offloads bandwidth from your backend servers and is the standard approach for file upload features in web apps.
If your backend generates SAS tokens, it should do so using Managed Identity rather than a stored account key. A backend running on Azure App Service or Azure Functions can be assigned a managed identity that has the “Storage Blob Delegator” role on the storage account — allowing it to generate user delegation SAS tokens without ever holding a key. This eliminates a whole class of credential-leak vulnerabilities.
Common mistakes
- Generating SAS tokens with very long expiry times. A SAS token valid for one year is almost as dangerous as sharing the account key. If it leaks, an attacker has access for a year. Use the shortest expiry that’s practical for your use case — minutes for upload flows, hours for temporary downloads, days at most for partner access.
- Putting SAS tokens in client-side JavaScript. Anything embedded in a web page is visible to users. SAS tokens in JavaScript source are easily extracted. Generate them server-side and return them only when needed, or use user delegation SAS with short expiry so leaked tokens expire quickly.
- Using account SAS when service SAS is enough. Account SAS grants access across multiple services and resource types. If you only need blob read access, use a service SAS or a blob SAS. Principle of least privilege applies to SAS tokens too.
- Not logging SAS token generation. Azure Storage logs don’t tell you what a SAS token was used for once it leaves your system. Log every token you generate — the blob path, expiry, permissions, and who requested it — so you have an audit trail if something goes wrong.
Summary
- SAS tokens grant time-limited, permission-scoped access to Azure Storage resources without exposing account keys.
- There are three types: service SAS (one service), account SAS (multiple services), and user delegation SAS (AD-backed, revocable — preferred).
- Stored access policies make SAS tokens revocable before expiry; without a stored policy, the only way to invalidate a token is to rotate the account key.
- The pre-signed URL pattern — generate a short-lived token server-side, let the client upload directly — is the standard approach for file upload features.
Frequently asked questions
Can I revoke a SAS token once it has been issued?
An ad-hoc SAS token (generated directly from an account key) cannot be revoked before its expiry — unless you rotate the storage account key, which invalidates all SAS tokens signed with that key. A service SAS linked to a stored access policy can be revoked instantly by deleting the policy. This is why stored access policies are preferred for production use.
What is the difference between a service SAS and an account SAS?
A service SAS grants access to a specific resource type (blobs, files, queues, or tables) within one service. An account SAS can span multiple services and resource types in the same account. Account SAS tokens are more powerful and should be used with extra caution — the blast radius of a leaked account SAS is larger.
Should I put SAS tokens in my app's environment variables?
SAS tokens in environment variables are better than hardcoding them, but the best approach is to generate short-lived SAS tokens on demand from a backend service using Managed Identity — never ship a long-lived SAS token in a client application or environment file that gets committed to source control.