Azure Storage Blob TS
MicrosoftOfficialCreated by Microsoft
- Skill
- Tool integration
- Cloud and DevOps
- MIT
- No issues found
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
Download the skill as a ZIP:
https://autogineer.com/agent-skills/microsoft/azure-storage-blob-ts/downloadUnzip 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/identityCurrent 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 productionAuthentication
Microsoft Entra Token Credential (Recommended)
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
Use
DefaultAzureCredentialfor local development; useManagedIdentityCredentialorWorkloadIdentityCredentialfor productionUse streaming for large files —
uploadStream/downloadToFilefor files > 256MBSet appropriate content types — Use
setHTTPHeadersfor correct MIME typesUse SAS tokens for client access — Generate short-lived tokens for browser uploads
Handle errors gracefully — Check
RestError.statusCodefor specific handlingUse
*IfNotExistsmethods — For idempotent container/blob creationClose clients — Not required but good practice in long-running apps
Platform Differences
| Feature | Node.js | Browser |
|---|---|---|
StorageSharedKeyCredential | ✅ | ❌ |
uploadFile() | ✅ | ❌ |
uploadStream() | ✅ | ❌ |
downloadToFile() | ✅ | ❌ |
downloadToBuffer() | ✅ | ❌ |
uploadData() | ✅ | ✅ |
| SAS generation | ✅ | ❌ |
| DefaultAzureCredential | ✅ | ❌ |
| Anonymous/SAS access | ✅ | ✅ |
Files
- ATTRIBUTION.mdAdded by AutoGineer982 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md12.8 KiB
- references/sas-tokens.md12.7 KiB
- references/streaming.md10.2 KiB
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/identitySAS Types Overview
| SAS Type | Scope | Use Case |
|---|---|---|
| Service SAS | Single blob or container | Grant access to specific resources |
| Account SAS | Entire storage account | Grant broad access to multiple services |
| User Delegation SAS | Single blob or container | Most secure, uses Entra ID credentials |
User Delegation SAS (Recommended)
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)
| Permission | Code | Description |
|---|---|---|
| Read | r | Read blob content and metadata |
| Add | a | Add blocks to append blob |
| Create | c | Create new blob |
| Write | w | Write to blob |
| Delete | d | Delete blob |
| Delete Version | x | Delete blob version |
| Tag | t | Read/write blob tags |
| Move | m | Move blob |
| Execute | e | Execute (for DataLake) |
| Set Immutability | i | Set immutability policy |
| Permanent Delete | y | Permanently 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:
| Permission | Code | Description |
|---|---|---|
| List | l | List blobs in container |
const permissions = ContainerSASPermissions.parse("rl"); // read and listAccount Permissions (AccountSASPermissions)
| Permission | Code | Description |
|---|---|---|
| Read | r | Read |
| Write | w | Write |
| Delete | d | Delete |
| Delete Version | x | Delete version |
| List | l | List |
| Add | a | Add |
| Create | c | Create |
| Update | u | Update |
| Process | p | Process messages |
| Tag | t | Tags |
| Filter | f | Filter by tags |
| Set Immutability | i | Immutability 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
Prefer User Delegation SAS - More secure, tied to Entra ID, auditable
Use shortest possible expiry - Minimize exposure window
Use HTTPS only - Set
protocol: SASProtocol.HttpsApply least privilege - Grant only necessary permissions
Use IP restrictions - When client IPs are known
Rotate keys regularly - If using account key SAS
Store SAS securely - Never expose in client-side code permanently
Set start time - Prevent "not yet valid" errors due to clock skew
Use stored access policies - For container-level SAS management
Security Considerations
| Risk | Mitigation |
|---|---|
| SAS token leaked | Short expiry, IP restrictions, HTTPS only |
| Over-privileged access | Least privilege permissions |
| Account key compromise | Use User Delegation SAS instead |
| Clock skew issues | Set startsOn slightly in the past |
| Token reuse | Use unique blob names or short expiry |
See Also
Streaming Patterns - Upload/download with SAS
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