Resolving Azure SAS Tokens Returning 403 Authorization Failure

Use this when an Azure Storage SAS URL returns 403 even though the token looks valid.

Quick Read

  • Symptom: Use this when an Azure Storage SAS URL returns 403 even though the token looks valid.
  • Check first: Confirm the HTTP method matches the SAS permission, such as GET with `r`, PUT with `w`, DELETE with `d`, or list operations with `l`.
  • Risk: Security-sensitive

Symptoms

An Azure Storage SAS URL can return 403 even when the token format looks correct. Most failures come down to a mismatch between the request and the token permissions, token scope, start or expiry time, stored access policy, URL encoding, or storage account network rules.

Environment

Azure Storage accounts using service SAS, account SAS, user delegation SAS, private containers, Azure CLI, Azure Storage Explorer, custom applications, storage firewalls, or private endpoints.

Most Likely Causes

A 403 authorization failure usually means the request does not match what the SAS token and storage account allow. Common causes include missing sp permissions, the wrong sr resource scope, a token start time in the future, an expired token, stored access policy changes, URL encoding problems, request method mismatch, blocked client IP, private endpoint routing, or confusion between Azure RBAC and SAS authorization.

What to Check First

  1. Confirm the HTTP method matches the SAS permission, such as GET with `r`, PUT with `w`, DELETE with `d`, or list operations with `l`.
  2. Check the token time window, especially `st` and `se`, and account for client/server clock skew.
  3. Confirm whether the token is signed for the exact blob, container, service, or account scope being requested.
  4. List storage account network rules before changing them and test from a known allowed network path.

Fix Steps

  1. Inspect the SAS token fields without sharing the signature

    Look at the non-secret fields in the query string, such as sp, st, se, sr, sv, and si. Do not paste the full token, sig, or full URL into tickets, chat, screenshots, or logs.

  2. Map the SAS fields to the failing request

    Before regenerating anything, map the visible SAS fields to the operation that fails. Treat the sig value as secret and do not paste it into tickets or logs.

    Expected output:

    Useful field checks: sp is permissions, st is start time, se is expiry, sr is resource scope, sv is service version, si is stored access policy, and sig is the secret signature. A GET needs r; a list operation needs l; an expired se or future st can produce 403; a changed si policy can invalidate a previously working URL.

    Rollback or backout:

    No change is made in this step.

  3. Check storage account network rules before changing anything

    A valid SAS token still fails if the request is blocked by storage account network controls. Start with a read-only list of network rules and confirm whether the client IP, subnet, private endpoint, or trusted service path is allowed.

    Safe to run: read-only

    az storage account network-rule list --resource-group <resource-group> --account-name <storage-account>
    Expected output:

    defaultAction shows whether unmatched traffic is denied or allowed. ipRules lists allowed public IP ranges. virtualNetworkRules lists allowed subnets. If the client source is not represented and default action is Deny, the SAS can fail even when the token itself is valid.

    Rollback or backout:

    No change is made in this step.

  4. Validate the request against the intended resource scope

    Use the token only in a controlled shell session and avoid echoing it through pipelines that can expose it in history or process listings. Prefer an environment variable or secure secret store during testing.

    Security-sensitive: review before running

    $env:AZURE_STORAGE_SAS_TOKEN = "<sas-token-without-leading-question-mark>"
    az storage blob show --account-name <storage-account> --container-name <container> --name <blob-name> --sas-token $env:AZURE_STORAGE_SAS_TOKEN
    Expected output:

    A successful read returns blob properties such as name, container, content length, content type, and last modified time. AuthorizationFailure or AuthenticationFailed means the request still does not match token, policy, network, or time-window requirements.

    Rollback or backout:

    Clear the shell variable after testing and avoid saving the token in command history, transcripts, or ticket notes.

  5. Regenerate a least-privilege SAS only after the cause is understood

    Generating a SAS creates an access credential. Keep the permission set as narrow as possible and avoid broad rwdl permissions unless the workflow truly needs them.

    Security-sensitive: review before running

    az storage container generate-sas --account-name <storage-account> --name <container> --permissions r --expiry <yyyy-mm-ddTHH:mmZ> --https-only --output tsv
    Expected output:

    The command returns a SAS query string. Treat it like a password. The example grants read-only container access until the specified expiry and requires HTTPS.

    Rollback or backout:

    If the SAS is policy-bound, revoke or update the stored access policy. If account keys were used and the token leaked, assess dependent tokens before rotating keys.

  6. Add a client IP rule only as an approved remediation

    Only add a network rule after the read-only check proves the client source is blocked and the change is approved. This modifies the storage account firewall.

    Changes system state: review before running

    az storage account network-rule add --resource-group <resource-group> --account-name <storage-account> --ip-address <client-ip-address>
    Expected output:

    A follow-up az storage account network-rule list should show the added IP rule. The original SAS request should then be retested from the same client path and should no longer fail due to network rules.

    Rollback or backout:

    Remove the temporary IP rule after testing with az storage account network-rule remove --resource-group <resource-group> --account-name <storage-account> --ip-address <client-ip-address>.

Validation

  • Repeat the exact failing request from the same client and confirm HTTP 403 no longer appears.
  • Check Storage diagnostic logs or Log Analytics for `AuthorizationFailure`, `AuthenticationFailed`, or network-rule denial entries after the retry.
  • Confirm the fix did not require enabling anonymous public access on a private container.

Logs to Check

  • Storage account diagnostic logs for authorization and network-rule failures.
  • Application logs for the exact URL path, HTTP method, and response code without logging the SAS signature.
  • Private endpoint DNS and network logs if the request path should stay private.

Rollback and Escalation

  • Remove temporary storage firewall IP rules after testing.
  • Revoke or update stored access policies when a policy-scoped SAS was issued incorrectly.
  • Rotate storage account keys only after assessing blast radius for all dependent SAS tokens.

Escalate When

  • Escalate before widening network access on production storage accounts.
  • Escalate if the SAS token may have been exposed in logs, tickets, chat, screenshots, or shell history.
  • Escalate if the application requires broad write/delete/list permissions and no stored access policy exists.

Edge Cases

  • A token with a start time set too close to the current time can fail on clients with clock skew.
  • A private container can still be accessed with a valid SAS token. Public container access is not required for normal SAS workflows.
  • Stored access policy changes can invalidate or restrict policy-bound SAS tokens even when the URL itself has not changed.
  • If the same SAS fails in both the application and Azure Storage Explorer from the same network, focus on token scope, permission, time window, stored access policy, or network rules. If it only fails in the application, check URL encoding, HTTP method, and how the app constructs the request.

Notes from the Field

  • Do not regenerate tokens repeatedly before checking the storage firewall. A valid SAS token can still fail when the request never passes account-level network controls.
  • When testing in a shell, avoid patterns that print or pipe the SAS token. Treat generated SAS values like passwords.