Generated banner for Azure Storage Blob TS
Generated logo for Azure Storage Blob TS

Azure Storage Blob TS

MicrosoftOfficialCreated by Microsoft

  • Skill
  • Tool integration
  • Cloud and DevOps
  • MIT
  • No issues found

From the author

Azure Blob Storage JavaScript/TypeScript SDK (@azure/storage-blob) for blob operations. Use for uploading, downloading, listing, and managing blobs and containers. Supports block blobs, append blobs, page blobs, SAS tokens, and streaming. Triggers: "blob storage", "@azure/storage-blob", "BlobServiceClient", "ContainerClient", "upload blob", "download blob", "SAS token", "block blob".
— the description by Microsoft

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The @azure/storage-blob SDK provides a comprehensive interface for interacting with Azure Blob Storage. It supports various authentication methods, including Microsoft Entra ID and connection strings, and facilitates operations such as uploading, downloading, listing, and managing blobs and containers. The library is designed for both Node.js and browser environments, offering specialized features like streaming for large files, SAS token generation for secure access, and support for block, append, and page blobs.

What it does

  • Manage storage containers and blobs via a hierarchical client structure.
  • Upload and download data using buffers, streams, or direct file paths.
  • Generate Service, Account, and User Delegation SAS tokens for secure access.
  • Configure blob properties, metadata, and HTTP headers.
  • Support for block, append, and page blob types.
  • Handle storage errors with specific status code reporting.

When to use it

  • When building applications that require cloud-based object storage on Azure.
  • When you need to implement secure, time-limited access to storage resources via SAS tokens.
  • When handling large file uploads or downloads that require streaming.
  • When integrating Azure storage operations into TypeScript or JavaScript projects.

Advantages

  • Official Microsoft support for Azure Blob Storage.
  • Strong TypeScript support with comprehensive type definitions.
  • Flexible authentication options including modern Entra ID integration.
  • Optimized for large data transfers with built-in streaming and concurrency controls.
  • Cross-platform compatibility for both Node.js and browser environments.

Usage examples

“How do I upload a local file to Azure Blob Storage using the SDK?”
The agent provides a code snippet using BlockBlobClient.uploadFile, demonstrating how to initialize the client and perform the upload operation.
“Show me how to generate a read-only SAS token for a specific blob.”
The agent provides a function using generateBlobSASQueryParameters, specifying the container, blob name, read permissions, and expiration time.
“How can I list all blobs in a container that start with a specific prefix?”
The agent demonstrates using the listBlobsFlat method on a ContainerClient with a prefix filter option.
“What is the best way to handle errors when creating a container?”
The agent shows a try-catch block using RestError to check for specific HTTP status codes like 404, 409, or 403.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/microsoft/azure-storage-blob-ts/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip azure-storage-blob-ts.zip -d .agents/skills

Documentation by Microsoft

@azure/storage-blob (TypeScript/JavaScript)

SDK for Azure Blob Storage operations — upload, download, list, and manage blobs and containers.

Installation

npm install @azure/storage-blob @azure/identity

Current Version: 12.x
Node.js: >= 18.0.0

Environment Variables

AZURE_STORAGE_ACCOUNT_NAME=<account-name>
AZURE_STORAGE_ACCOUNT_KEY=<account-key>
# OR connection string
AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=...
AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in production

Authentication

import { BlobServiceClient } from "@azure/storage-blob";
import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";

// Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS=<specific_credential>
const credential = new DefaultAzureCredential({requiredEnvVars: ["AZURE_TOKEN_CREDENTIALS"]});
// Or use a specific credential directly in production:
// See https://learn.microsoft.com/javascript/api/overview/azure/identity-readme?view=azure-node-latest#credential-classes
// const credential = new ManagedIdentityCredential();

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const client = new BlobServiceClient(
  `https://${accountName}.blob.core.windows.net`,
  credential
);
Connection String
import { BlobServiceClient } from "@azure/storage-blob";

const client = BlobServiceClient.fromConnectionString(
  process.env.AZURE_STORAGE_CONNECTION_STRING!
);
StorageSharedKeyCredential (Node.js only)
import { BlobServiceClient, StorageSharedKeyCredential } from "@azure/storage-blob";

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY!;

const sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);
const client = new BlobServiceClient(
  `https://${accountName}.blob.core.windows.net`,
  sharedKeyCredential
);
SAS Token
import { BlobServiceClient } from "@azure/storage-blob";

const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME!;
const sasToken = process.env.AZURE_STORAGE_SAS_TOKEN!; // starts with "?"

const client = new BlobServiceClient(
  `https://${accountName}.blob.core.windows.net${sasToken}`
);

Client Hierarchy

BlobServiceClient (account level)
└── ContainerClient (container level)
    └── BlobClient (blob level)
        ├── BlockBlobClient (block blobs - most common)
        ├── AppendBlobClient (append-only blobs)
        └── PageBlobClient (page blobs - VHDs)

Container Operations

Create Container
const containerClient = client.getContainerClient("my-container");
await containerClient.create();

// Or create if not exists
await containerClient.createIfNotExists();
List Containers
for await (const container of client.listContainers()) {
  console.log(container.name);
}

// With prefix filter
for await (const container of client.listContainers({ prefix: "logs-" })) {
  console.log(container.name);
}
Delete Container
await containerClient.delete();
// Or delete if exists
await containerClient.deleteIfExists();

Blob Operations

Upload Blob (Simple)
const containerClient = client.getContainerClient("my-container");
const blockBlobClient = containerClient.getBlockBlobClient("my-file.txt");

// Upload string
await blockBlobClient.upload("Hello, World!", 13);

// Upload Buffer
const buffer = Buffer.from("Hello, World!");
await blockBlobClient.upload(buffer, buffer.length);
Upload from File (Node.js only)
const blockBlobClient = containerClient.getBlockBlobClient("uploaded-file.txt");
await blockBlobClient.uploadFile("/path/to/local/file.txt");
Upload from Stream (Node.js only)
import * as fs from "fs";

const blockBlobClient = containerClient.getBlockBlobClient("streamed-file.txt");
const readStream = fs.createReadStream("/path/to/local/file.txt");

await blockBlobClient.uploadStream(readStream, 4 * 1024 * 1024, 5, {
  // bufferSize: 4MB, maxConcurrency: 5
  onProgress: (progress) => console.log(`Uploaded ${progress.loadedBytes} bytes`),
});
Upload from Browser
const blockBlobClient = containerClient.getBlockBlobClient("browser-upload.txt");

// From File input
const fileInput = document.getElementById("fileInput") as HTMLInputElement;
const file = fileInput.files![0];
await blockBlobClient.uploadData(file);

// From Blob/ArrayBuffer
const arrayBuffer = new ArrayBuffer(1024);
await blockBlobClient.uploadData(arrayBuffer);
Download Blob
const blobClient = containerClient.getBlobClient("my-file.txt");
const downloadResponse = await blobClient.download();

// Read as string (browser & Node.js)
const downloaded = await streamToText(downloadResponse.readableStreamBody!);

async function streamToText(readable: NodeJS.ReadableStream): Promise<string> {
  const chunks: Buffer[] = [];
  for await (const chunk of readable) {
    chunks.push(Buffer.from(chunk));
  }
  return Buffer.concat(chunks).toString("utf-8");
}
Download to File (Node.js only)
const blockBlobClient = containerClient.getBlockBlobClient("my-file.txt");
await blockBlobClient.downloadToFile("/path/to/local/destination.txt");
Download to Buffer (Node.js only)
const blockBlobClient = containerClient.getBlockBlobClient("my-file.txt");
const buffer = await blockBlobClient.downloadToBuffer();
console.log(buffer.toString());
List Blobs
// List all blobs
for await (const blob of containerClient.listBlobsFlat()) {
  console.log(blob.name, blob.properties.contentLength);
}

// List with prefix
for await (const blob of containerClient.listBlobsFlat({ prefix: "logs/" })) {
  console.log(blob.name);
}

// List by hierarchy (virtual directories)
for await (const item of containerClient.listBlobsByHierarchy("/")) {
  if (item.kind === "prefix") {
    console.log(`Directory: ${item.name}`);
  } else {
    console.log(`Blob: ${item.name}`);
  }
}
Delete Blob
const blobClient = containerClient.getBlobClient("my-file.txt");
await blobClient.delete();

// Delete if exists
await blobClient.deleteIfExists();

// Delete with snapshots
await blobClient.delete({ deleteSnapshots: "include" });
Copy Blob
const sourceBlobClient = containerClient.getBlobClient("source.txt");
const destBlobClient = containerClient.getBlobClient("destination.txt");

// Start copy operation
const copyPoller = await destBlobClient.beginCopyFromURL(sourceBlobClient.url);
await copyPoller.pollUntilDone();

Blob Properties & Metadata

Get Properties
const blobClient = containerClient.getBlobClient("my-file.txt");
const properties = await blobClient.getProperties();

console.log("Content-Type:", properties.contentType);
console.log("Content-Length:", properties.contentLength);
console.log("Last Modified:", properties.lastModified);
console.log("ETag:", properties.etag);
Set Metadata
await blobClient.setMetadata({
  author: "John Doe",
  category: "documents",
});
Set HTTP Headers
await blobClient.setHTTPHeaders({
  blobContentType: "text/plain",
  blobCacheControl: "max-age=3600",
  blobContentDisposition: "attachment; filename=download.txt",
});

SAS Token Generation (Node.js only)

Generate Blob SAS
import {
  BlobSASPermissions,
  generateBlobSASQueryParameters,
  StorageSharedKeyCredential,
} from "@azure/storage-blob";

const sharedKeyCredential = new StorageSharedKeyCredential(accountName, accountKey);

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    blobName: "my-file.txt",
    permissions: BlobSASPermissions.parse("r"), // read only
    startsOn: new Date(),
    expiresOn: new Date(Date.now() + 3600 * 1000), // 1 hour
  },
  sharedKeyCredential
).toString();

const sasUrl = `https://${accountName}.blob.core.windows.net/my-container/my-file.txt?${sasToken}`;
Generate Container SAS
import { ContainerSASPermissions, generateBlobSASQueryParameters } from "@azure/storage-blob";

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    permissions: ContainerSASPermissions.parse("racwdl"), // read, add, create, write, delete, list
    expiresOn: new Date(Date.now() + 24 * 3600 * 1000), // 24 hours
  },
  sharedKeyCredential
).toString();
Generate Account SAS
import {
  AccountSASPermissions,
  AccountSASResourceTypes,
  AccountSASServices,
  generateAccountSASQueryParameters,
} from "@azure/storage-blob";

const sasToken = generateAccountSASQueryParameters(
  {
    services: AccountSASServices.parse("b").toString(), // blob
    resourceTypes: AccountSASResourceTypes.parse("sco").toString(), // service, container, object
    permissions: AccountSASPermissions.parse("rwdlacupi"), // all permissions
    expiresOn: new Date(Date.now() + 24 * 3600 * 1000),
  },
  sharedKeyCredential
).toString();

Blob Types

Block Blob (Default)

Most common type for text and binary files.

const blockBlobClient = containerClient.getBlockBlobClient("document.pdf");
await blockBlobClient.uploadFile("/path/to/document.pdf");
Append Blob

Optimized for append operations (logs, audit trails).

const appendBlobClient = containerClient.getAppendBlobClient("app.log");

// Create the append blob
await appendBlobClient.create();

// Append data
await appendBlobClient.appendBlock("Log entry 1\n", 12);
await appendBlobClient.appendBlock("Log entry 2\n", 12);
Page Blob

Fixed-size blobs for random read/write (VHDs).

const pageBlobClient = containerClient.getPageBlobClient("disk.vhd");

// Create 512-byte aligned page blob
await pageBlobClient.create(1024 * 1024); // 1MB

// Write pages (must be 512-byte aligned)
const buffer = Buffer.alloc(512);
await pageBlobClient.uploadPages(buffer, 0, 512);

Error Handling

import { RestError } from "@azure/storage-blob";

try {
  await containerClient.create();
} catch (error) {
  if (error instanceof RestError) {
    switch (error.statusCode) {
      case 404:
        console.log("Container not found");
        break;
      case 409:
        console.log("Container already exists");
        break;
      case 403:
        console.log("Access denied");
        break;
      default:
        console.error(`Storage error ${error.statusCode}: ${error.message}`);
    }
  }
  throw error;
}

TypeScript Types Reference

import {
  // Clients
  BlobServiceClient,
  ContainerClient,
  BlobClient,
  BlockBlobClient,
  AppendBlobClient,
  PageBlobClient,

  // Authentication
  StorageSharedKeyCredential,
  AnonymousCredential,

  // SAS
  BlobSASPermissions,
  ContainerSASPermissions,
  AccountSASPermissions,
  AccountSASServices,
  AccountSASResourceTypes,
  generateBlobSASQueryParameters,
  generateAccountSASQueryParameters,

  // Options & Responses
  BlobDownloadResponseParsed,
  BlobUploadCommonResponse,
  ContainerCreateResponse,
  BlobItem,
  ContainerItem,

  // Errors
  RestError,
} from "@azure/storage-blob";

Best Practices

  1. Use DefaultAzureCredential for local development; use ManagedIdentityCredential or WorkloadIdentityCredential for production

  2. Use streaming for large files — uploadStream/downloadToFile for files > 256MB

  3. Set appropriate content types — Use setHTTPHeaders for correct MIME types

  4. Use SAS tokens for client access — Generate short-lived tokens for browser uploads

  5. Handle errors gracefully — Check RestError.statusCode for specific handling

  6. Use *IfNotExists methods — For idempotent container/blob creation

  7. Close clients — Not required but good practice in long-running apps

Platform Differences

FeatureNode.jsBrowser
StorageSharedKeyCredential✅❌
uploadFile()✅❌
uploadStream()✅❌
downloadToFile()✅❌
downloadToBuffer()✅❌
uploadData()✅✅
SAS generation✅❌
DefaultAzureCredential✅❌
Anonymous/SAS access✅✅

Files

references/sas-tokens.md

@azure/storage-blob - SAS Token Patterns

Reference documentation for generating Shared Access Signatures (SAS) in the Azure Blob Storage TypeScript SDK.

Source: Azure SDK for JS - storage-blob


Installation

npm install @azure/storage-blob @azure/identity

SAS Types Overview

SAS TypeScopeUse Case
Service SASSingle blob or containerGrant access to specific resources
Account SASEntire storage accountGrant broad access to multiple services
User Delegation SASSingle blob or containerMost secure, uses Entra ID credentials

Most secure option—uses Entra ID credentials instead of account keys.

Generate User Delegation Key
import {
  BlobServiceClient,
  generateBlobSASQueryParameters,
  BlobSASPermissions,
  SASProtocol,
} from "@azure/storage-blob";
import { DefaultAzureCredential } from "@azure/identity";

const credential = new DefaultAzureCredential();
const blobServiceClient = new BlobServiceClient(
  `https://${accountName}.blob.core.windows.net`,
  credential
);

// Get user delegation key (valid for up to 7 days)
const startsOn = new Date();
const expiresOn = new Date(startsOn.valueOf() + 3600 * 1000); // 1 hour

const userDelegationKey = await blobServiceClient.getUserDelegationKey(
  startsOn,
  expiresOn
);
Generate User Delegation SAS for Blob
const containerName = "my-container";
const blobName = "my-blob.txt";

const sasToken = generateBlobSASQueryParameters(
  {
    containerName,
    blobName,
    permissions: BlobSASPermissions.parse("r"), // read only
    startsOn,
    expiresOn,
    protocol: SASProtocol.Https,
  },
  userDelegationKey,
  accountName
).toString();

const sasUrl = `https://${accountName}.blob.core.windows.net/${containerName}/${blobName}?${sasToken}`;
console.log("SAS URL:", sasUrl);

Service SAS (Account Key)

Uses storage account key. Less secure but simpler for some scenarios.

Generate Blob SAS
import {
  BlobServiceClient,
  generateBlobSASQueryParameters,
  BlobSASPermissions,
  StorageSharedKeyCredential,
} from "@azure/storage-blob";

const accountName = process.env["STORAGE_ACCOUNT_NAME"]!;
const accountKey = process.env["STORAGE_ACCOUNT_KEY"]!;

const sharedKeyCredential = new StorageSharedKeyCredential(
  accountName,
  accountKey
);

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    blobName: "my-blob.txt",
    permissions: BlobSASPermissions.parse("racwd"), // read, add, create, write, delete
    startsOn: new Date(),
    expiresOn: new Date(Date.now() + 3600 * 1000), // 1 hour
  },
  sharedKeyCredential
).toString();

const sasUrl = `https://${accountName}.blob.core.windows.net/my-container/my-blob.txt?${sasToken}`;
Generate Container SAS
import {
  ContainerSASPermissions,
  generateBlobSASQueryParameters,
} from "@azure/storage-blob";

const containerSasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    permissions: ContainerSASPermissions.parse("rl"), // read, list
    startsOn: new Date(),
    expiresOn: new Date(Date.now() + 86400 * 1000), // 24 hours
  },
  sharedKeyCredential
).toString();

const containerSasUrl = `https://${accountName}.blob.core.windows.net/my-container?${containerSasToken}`;

Account SAS

Grants access to multiple services (blob, queue, table, file).

import {
  generateAccountSASQueryParameters,
  AccountSASPermissions,
  AccountSASServices,
  AccountSASResourceTypes,
  StorageSharedKeyCredential,
} from "@azure/storage-blob";

const accountSasToken = generateAccountSASQueryParameters(
  {
    services: AccountSASServices.parse("btqf").toString(), // blob, table, queue, file
    resourceTypes: AccountSASResourceTypes.parse("sco").toString(), // service, container, object
    permissions: AccountSASPermissions.parse("rwdlacupi"), // all permissions
    startsOn: new Date(),
    expiresOn: new Date(Date.now() + 3600 * 1000),
    protocol: SASProtocol.Https,
  },
  sharedKeyCredential
).toString();

const accountSasUrl = `https://${accountName}.blob.core.windows.net?${accountSasToken}`;

SAS Permissions

Blob Permissions (BlobSASPermissions)
PermissionCodeDescription
ReadrRead blob content and metadata
AddaAdd blocks to append blob
CreatecCreate new blob
WritewWrite to blob
DeletedDelete blob
Delete VersionxDelete blob version
TagtRead/write blob tags
MovemMove blob
ExecuteeExecute (for DataLake)
Set ImmutabilityiSet immutability policy
Permanent DeleteyPermanently delete (soft-deleted)
// Parse from string
const permissions = BlobSASPermissions.parse("rwd");

// Build programmatically
const permissions = new BlobSASPermissions();
permissions.read = true;
permissions.write = true;
permissions.delete = true;
Container Permissions (ContainerSASPermissions)

Same as blob permissions, plus:

PermissionCodeDescription
ListlList blobs in container
const permissions = ContainerSASPermissions.parse("rl"); // read and list
Account Permissions (AccountSASPermissions)
PermissionCodeDescription
ReadrRead
WritewWrite
DeletedDelete
Delete VersionxDelete version
ListlList
AddaAdd
CreatecCreate
UpdateuUpdate
ProcesspProcess messages
TagtTags
FilterfFilter by tags
Set ImmutabilityiImmutability policy

SAS Options

Content Headers

Override response headers:

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    blobName: "document.pdf",
    permissions: BlobSASPermissions.parse("r"),
    expiresOn: new Date(Date.now() + 3600 * 1000),
    
    // Override response headers
    contentDisposition: "attachment; filename=download.pdf",
    contentType: "application/pdf",
    cacheControl: "max-age=3600",
    contentEncoding: "gzip",
    contentLanguage: "en-US",
  },
  sharedKeyCredential
).toString();
IP Restrictions

Restrict SAS to specific IP addresses:

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    blobName: "my-blob.txt",
    permissions: BlobSASPermissions.parse("r"),
    expiresOn: new Date(Date.now() + 3600 * 1000),
    
    // Single IP
    ipRange: { start: "168.1.5.60" },
    
    // IP range
    // ipRange: { start: "168.1.5.60", end: "168.1.5.70" },
  },
  sharedKeyCredential
).toString();
Protocol Restriction

Require HTTPS:

import { SASProtocol } from "@azure/storage-blob";

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    blobName: "my-blob.txt",
    permissions: BlobSASPermissions.parse("r"),
    expiresOn: new Date(Date.now() + 3600 * 1000),
    protocol: SASProtocol.Https, // HTTPS only
    // protocol: SASProtocol.HttpsAndHttp, // Allow both
  },
  sharedKeyCredential
).toString();
Blob Versioning

Access specific blob version or snapshot:

const sasToken = generateBlobSASQueryParameters(
  {
    containerName: "my-container",
    blobName: "my-blob.txt",
    permissions: BlobSASPermissions.parse("r"),
    expiresOn: new Date(Date.now() + 3600 * 1000),
    
    // For snapshots
    snapshotTime: "2023-01-15T10:30:00.0000000Z",
    
    // For versions
    // versionId: "2023-01-15T10:30:00.0000000Z",
  },
  sharedKeyCredential
).toString();

Using SAS URLs

Download with SAS
// Client-side (browser or Node.js)
const response = await fetch(sasUrl);
const blob = await response.blob();
Upload with SAS (Write Permission)
const sasUrlWithWrite = `https://${accountName}.blob.core.windows.net/container/blob.txt?${writeSasToken}`;

await fetch(sasUrlWithWrite, {
  method: "PUT",
  headers: {
    "x-ms-blob-type": "BlockBlob",
    "Content-Type": "text/plain",
  },
  body: "Hello, World!",
});
Create Anonymous Client with SAS
import { BlobClient } from "@azure/storage-blob";

// No credential needed - SAS in URL
const blobClient = new BlobClient(sasUrl);
const downloadResponse = await blobClient.download(0);

Complete Example

import {
  BlobServiceClient,
  generateBlobSASQueryParameters,
  BlobSASPermissions,
  ContainerSASPermissions,
  SASProtocol,
  StorageSharedKeyCredential,
} from "@azure/storage-blob";
import { DefaultAzureCredential } from "@azure/identity";

async function generateSasTokens() {
  const accountName = process.env["STORAGE_ACCOUNT_NAME"]!;
  const accountKey = process.env["STORAGE_ACCOUNT_KEY"]!;
  
  // Method 1: User Delegation SAS (recommended)
  const credential = new DefaultAzureCredential();
  const blobServiceClient = new BlobServiceClient(
    `https://${accountName}.blob.core.windows.net`,
    credential
  );
  
  const startsOn = new Date();
  const expiresOn = new Date(startsOn.valueOf() + 3600 * 1000);
  
  const userDelegationKey = await blobServiceClient.getUserDelegationKey(
    startsOn,
    expiresOn
  );
  
  const userDelegationSas = generateBlobSASQueryParameters(
    {
      containerName: "uploads",
      blobName: "user-file.txt",
      permissions: BlobSASPermissions.parse("r"),
      startsOn,
      expiresOn,
      protocol: SASProtocol.Https,
    },
    userDelegationKey,
    accountName
  ).toString();
  
  console.log("User Delegation SAS URL:");
  console.log(`https://${accountName}.blob.core.windows.net/uploads/user-file.txt?${userDelegationSas}`);
  
  // Method 2: Service SAS with account key
  const sharedKeyCredential = new StorageSharedKeyCredential(
    accountName,
    accountKey
  );
  
  // Read-only SAS for download
  const readSas = generateBlobSASQueryParameters(
    {
      containerName: "public-files",
      blobName: "document.pdf",
      permissions: BlobSASPermissions.parse("r"),
      expiresOn: new Date(Date.now() + 86400 * 1000), // 24 hours
      contentDisposition: "attachment; filename=download.pdf",
      protocol: SASProtocol.Https,
    },
    sharedKeyCredential
  ).toString();
  
  console.log("\nRead SAS URL:");
  console.log(`https://${accountName}.blob.core.windows.net/public-files/document.pdf?${readSas}`);
  
  // Write SAS for upload
  const writeSas = generateBlobSASQueryParameters(
    {
      containerName: "uploads",
      blobName: "new-upload.txt",
      permissions: BlobSASPermissions.parse("cw"), // create, write
      expiresOn: new Date(Date.now() + 3600 * 1000), // 1 hour
      protocol: SASProtocol.Https,
    },
    sharedKeyCredential
  ).toString();
  
  console.log("\nWrite SAS URL:");
  console.log(`https://${accountName}.blob.core.windows.net/uploads/new-upload.txt?${writeSas}`);
  
  // Container list SAS
  const listSas = generateBlobSASQueryParameters(
    {
      containerName: "public-files",
      permissions: ContainerSASPermissions.parse("rl"), // read, list
      expiresOn: new Date(Date.now() + 3600 * 1000),
      protocol: SASProtocol.Https,
    },
    sharedKeyCredential
  ).toString();
  
  console.log("\nContainer List SAS URL:");
  console.log(`https://${accountName}.blob.core.windows.net/public-files?${listSas}`);
}

generateSasTokens().catch(console.error);

Best Practices

  1. Prefer User Delegation SAS - More secure, tied to Entra ID, auditable

  2. Use shortest possible expiry - Minimize exposure window

  3. Use HTTPS only - Set protocol: SASProtocol.Https

  4. Apply least privilege - Grant only necessary permissions

  5. Use IP restrictions - When client IPs are known

  6. Rotate keys regularly - If using account key SAS

  7. Store SAS securely - Never expose in client-side code permanently

  8. Set start time - Prevent "not yet valid" errors due to clock skew

  9. Use stored access policies - For container-level SAS management


Security Considerations

RiskMitigation
SAS token leakedShort expiry, IP restrictions, HTTPS only
Over-privileged accessLeast privilege permissions
Account key compromiseUse User Delegation SAS instead
Clock skew issuesSet startsOn slightly in the past
Token reuseUse unique blob names or short expiry

See Also

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Node.js

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Microsoft
Publisher
Microsoft (Official)
Source
microsoft/skills · .github/plugins/azure-sdk-typescript/skills/azure-storage-blob-ts · commit 0696600
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Microsoft or Microsoft.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download azure-storage-blob-ts.zip