This article shows you how to connect to Azure Blob Storage by using the Azure Blob Storage client library for JavaScript. Once connected, your code can operate on containers, blobs, and features of the Blob Storage service.
For client (browser) applications, you need bundling tools.
Set up your project
Open a command prompt and change into your project folder. Change YOUR-DIRECTORY to your folder name:
cd YOUR-DIRECTORY
If you don't have a package.json file already in your directory, initialize the project to create the file:
npm init -y
Install TypeScript and the Azure Blob Storage client library for JavaScript with TypeScript types included:
npm install typescript @azure/storage-blob
If you want to use passwordless connections using Microsoft Entra ID, install the Azure Identity client library for JavaScript:
npm install @azure/identity
Authorize access and connect to Blob Storage
Microsoft Entra ID provides the most secure connection by managing the connection identity (managed identity). This passwordless functionality allows you to develop an application that doesn't require any secrets (keys or connection strings) stored in the code.
Set up identity access to the Azure cloud
To connect to Azure without passwords, you need to set up an Azure identity or use an existing identity. Once the identity is set up, make sure to assign the appropriate roles to the identity.
To authorize passwordless access with Microsoft Entra ID, you'll need to use an Azure credential. Which type of credential you need depends on where your application runs. Use this table as a guide.
Your storage resource needs to have one or more of the following Azure RBAC roles assigned to the identity resource you plan to connect with. Setup the Azure Storage roles for each identity you created in the previous step: Azure cloud, local development, on-premises.
After you complete the setup, each identity needs at least one of the appropriate roles:
Once your Azure storage account identity roles and your local environment are set up, create a TypeScript file which includes the @azure/identity package. Create a credential, such as the DefaultAzureCredential, to implement passwordless connections to Blob Storage. Use that credential to authenticate with a BlobServiceClient object.
// connect-with-default-azure-credential.js
// You must set up RBAC for your identity with one of the following roles:
// - Storage Blob Data Reader
// - Storage Blob Data Contributor
import { DefaultAzureCredential } from '@azure/identity';
import { BlobServiceClient } from '@azure/storage-blob';
import * as dotenv from 'dotenv';
dotenv.config();
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
const blobServiceClient = new BlobServiceClient(
`https://${accountName}.blob.core.chinacloudapi.cn`,
new DefaultAzureCredential()
);
async function main() {
const containerName = 'my-container';
const blobName = 'my-blob';
const timestamp = Date.now();
const fileName = `my-new-file-${timestamp}.txt`;
// create container client
const containerClient = await blobServiceClient.getContainerClient(
containerName
);
// create blob client
const blobClient = await containerClient.getBlockBlobClient(blobName);
// download file
const downloadResult = await blobClient.downloadToFile(fileName);
if (downloadResult.errorCode) throw Error(downloadResult.errorCode);
console.log(
`${fileName} downloaded ${downloadResult.contentType}, isCurrentVersion: ${downloadResult.isCurrentVersion}`
);
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
The dotenv package is used to read your storage account name from a .env file. This file should not be checked into source control. If you use a local service principal as part of your DefaultAzureCredential set up, any security information for that credential will also go into the .env file.
If you plan to deploy the application to servers and clients that run outside of Azure, create one of the credentials that meets your needs.
Create a StorageSharedKeyCredential from the storage account name and account key. Then pass the StorageSharedKeyCredential to the BlobServiceClient class constructor to create a client.
// connect-with-account-name-and-key.js
import {
BlobServiceClient,
StorageSharedKeyCredential
} from '@azure/storage-blob';
import * as dotenv from 'dotenv';
import path from 'path';
dotenv.config();
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY as string;
if (!accountName) throw Error('Azure Storage accountName not found');
if (!accountKey) throw Error('Azure Storage accountKey not found');
const sharedKeyCredential = new StorageSharedKeyCredential(
accountName,
accountKey
);
const blobServiceClient = new BlobServiceClient(
`https://${accountName}.blob.core.chinacloudapi.cn`,
sharedKeyCredential
);
async function main(): Promise<void> {
const containerName = 'my-container';
const blobName = 'my-blob';
const timestamp = Date.now();
const fileName = path.join(
__dirname,
'../files',
`my-new-file-${timestamp}.txt`
);
// create container client
const containerClient = await blobServiceClient.getContainerClient(
containerName
);
// create blob client
const blobClient = await containerClient.getBlockBlobClient(blobName);
// download file
const downloadResult = await blobClient.downloadToFile(fileName);
if (downloadResult.errorCode) throw Error(downloadResult.errorCode);
console.log(
`${fileName} downloaded, created on ${downloadResult.createdOn}}`
);
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
The dotenv package is used to read your storage account name and key from a .env file. This file should not be checked into source control.
For information about how to obtain account keys and best practice guidelines for properly managing and safeguarding your keys, see Manage storage account access keys.
Important
The account access key should be used with caution. If your account access key is lost or accidentally placed in an insecure location, your service may become vulnerable. Anyone who has the access key is able to authorize requests against the storage account, and effectively has access to all the data. DefaultAzureCredential provides enhanced security features and benefits and is the recommended approach for managing authorization to Azure services.
Create a Uri to your resource by using the blob service endpoint and SAS token. Then, create a BlobServiceClient with the Uri. The SAS token is a series of name/value pairs in the querystring in the format such as:
For scenarios where shared access signatures (SAS) are used, Azure recommends using a user delegation SAS. A user delegation SAS is secured with Microsoft Entra credentials instead of the account key. To learn more, see Create a user delegation SAS with JavaScript.
Create a ContainerClient object
You can create the ContainerClient object either from the BlobServiceClient, or directly.
Create ContainerClient object from BlobServiceClient
Create the ContainerClient object from the BlobServiceClient.
// Azure Storage dependency
import {
BlobServiceClient,
StorageSharedKeyCredential
} from '@azure/storage-blob';
// For development environment - include environment variables from .env
import * as dotenv from 'dotenv';
dotenv.config();
// Azure Storage resource name
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
// Azure Storage resource key
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY as string;
if (!accountKey) throw Error('Azure Storage accountKey not found');
// Create credential
const sharedKeyCredential = new StorageSharedKeyCredential(
accountName,
accountKey
);
const baseUrl = `https://${accountName}.blob.core.chinacloudapi.cn`;
const containerName = `my-container`;
// Create BlobServiceClient
const blobServiceClient = new BlobServiceClient(
`${baseUrl}`,
sharedKeyCredential
);
async function main(): Promise<void> {
try {
// Create container client
const containerClient = await blobServiceClient.getContainerClient(
containerName
);
// do something with containerClient...
let i = 1;
// List blobs in container
for await (const blob of containerClient.listBlobsFlat({
includeMetadata: true,
includeSnapshots: false,
includeTags: true,
includeVersions: false,
prefix: ''
})) {
console.log(`Blob ${i++}: ${blob.name}`);
}
} catch (err) {
console.log(err);
throw err;
}
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
// Azure Storage dependency
import { ContainerClient } from '@azure/storage-blob';
// Azure authentication for credential dependency
import { DefaultAzureCredential } from '@azure/identity';
// For development environment - include environment variables from .env
import * as dotenv from 'dotenv';
dotenv.config();
// Azure Storage resource name
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
// Azure SDK needs base URL
const baseUrl = `https://${accountName}.blob.core.chinacloudapi.cn`;
// Unique container name
const timeStamp = Date.now();
const containerName = `my-container`;
async function main(): Promise<void> {
try {
// create container client from DefaultAzureCredential
const containerClient = new ContainerClient(
`${baseUrl}/${containerName}`,
new DefaultAzureCredential()
);
// do something with containerClient...
let i = 1;
// List blobs in container
for await (const blob of containerClient.listBlobsFlat({
includeMetadata: true,
includeSnapshots: false,
includeTags: true,
includeVersions: false,
prefix: ''
})) {
console.log(`Blob ${i++}: ${blob.name}`);
}
} catch (err) {
console.log(err);
throw err;
}
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
// Azure Storage dependency
import {
ContainerClient,
StorageSharedKeyCredential
} from '@azure/storage-blob';
// For development environment - include environment variables from .env
import * as dotenv from 'dotenv';
dotenv.config();
// Azure Storage resource name
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
// Azure Storage resource key
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY as string;
if (!accountKey) throw Error('Azure Storage accountKey not found');
const sharedKeyCredential = new StorageSharedKeyCredential(
accountName,
accountKey
);
const baseUrl = `https://${accountName}.blob.core.chinacloudapi.cn`;
const containerName = `my-container`;
async function main(): Promise<void> {
try {
// create container from ContainerClient
const containerClient = new ContainerClient(
`${baseUrl}/${containerName}`,
sharedKeyCredential
);
// do something with containerClient...
let i = 1;
// List blobs in container
for await (const blob of containerClient.listBlobsFlat({
includeMetadata: true,
includeSnapshots: false,
includeTags: true,
includeVersions: false,
prefix: ''
})) {
console.log(`Blob ${i++}: ${blob.name}`);
}
} catch (err) {
console.log(err);
throw err;
}
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
Important
The account access key should be used with caution. If your account access key is lost or accidentally placed in an insecure location, your service may become vulnerable. Anyone who has the access key is able to authorize requests against the storage account, and effectively has access to all the data. DefaultAzureCredential provides enhanced security features and benefits and is the recommended approach for managing authorization to Azure services.
// Azure Storage dependency
import { ContainerClient } from '@azure/storage-blob';
// For development environment - include environment variables
import * as dotenv from 'dotenv';
dotenv.config();
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
// Container must exist prior to running this script
const containerName = `my-container`;
// SAS token must have LIST permissions on container that haven't expired
const sasToken = process.env.AZURE_STORAGE_SAS_TOKEN as string;
// Create SAS URL
const sasUrl = `https://${accountName}.blob.core.chinacloudapi.cn/${containerName}?${sasToken}`;
async function main(): Promise<void> {
try {
// create container client from SAS token
const containerClient = new ContainerClient(sasUrl);
// do something with containerClient...
let i = 1;
// List blobs in container
for await (const blob of containerClient.listBlobsFlat({
includeMetadata: true,
includeSnapshots: false,
includeTags: true,
includeVersions: false,
prefix: ''
})) {
console.log(`Blob ${i++}: ${blob.name}`);
}
} catch (err) {
console.log(err);
throw err;
}
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
Note
For scenarios where shared access signatures (SAS) are used, Azure recommends using a user delegation SAS. A user delegation SAS is secured with Microsoft Entra credentials instead of the account key. To learn more, see Create a user delegation SAS with JavaScript.
The dotenv package is used to read your storage account name from a .env file. This file should not be checked into source control.
Create a BlobClient object
You can create any of the BlobClient objects, listed below, either from a ContainerClient, or directly.
// Azure Storage dependency
import {
BlockBlobClient,
BlockBlobUploadHeaders,
BlockBlobUploadResponse
} from '@azure/storage-blob';
import { getBlockBlobClientFromDefaultAzureCredential } from './auth-get-client';
// For development environment - include environment variables from .env
import * as dotenv from 'dotenv';
dotenv.config();
// Container must exist prior to running this script
const containerName = `my-container`;
// Random blob name and contents
const timeStamp = Date.now();
const blobName = `${timeStamp}-my-blob.txt`;
const fileContentsAsString = 'Hello there.';
const blockBlobClient: BlockBlobClient =
getBlockBlobClientFromDefaultAzureCredential(containerName, blobName);
async function main(
blockBlobClient: BlockBlobClient
): Promise<BlockBlobUploadHeaders> {
// Get file url - available before contents are uploaded
console.log(`blob.url: ${blockBlobClient.url}`);
// Upload file contents
const result: BlockBlobUploadHeaders = await blockBlobClient.upload(
fileContentsAsString,
fileContentsAsString.length
);
if (result.errorCode) throw Error(result.errorCode);
// Get results
return result;
}
main(blockBlobClient)
.then((result) => {
console.log(result);
console.log(`success`);
})
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
/*
Response looks like this:
{
etag: '"0x8DAD247F1F4896E"',
lastModified: 2022-11-29T20:26:07.000Z,
contentMD5: <Buffer 9d 6a 29 63 87 20 77 db 67 4a 27 a3 9c 49 2e 61>,
clientRequestId: 'a07fdd1f-5937-44c7-984f-0699a48a05c0',
requestId: '3580e726-201e-0045-1a30-0474f6000000',
version: '2021-04-10',
date: 2022-11-29T20:26:06.000Z,
isServerEncrypted: true,
'content-length': '0',
server: 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0',
'x-ms-content-crc64': 'BLv7vb1ONT8=',
body: undefined
}
*/
// Azure Storage dependency
import {
BlockBlobClient,
BlockBlobUploadHeaders,
BlockBlobUploadResponse,
StorageSharedKeyCredential
} from '@azure/storage-blob';
// For development environment - include environment variables from .env
import * as dotenv from 'dotenv';
dotenv.config();
// Azure Storage resource name
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
if (!accountName) throw Error('Azure Storage accountName not found');
// Azure Storage resource key
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY as string;
if (!accountKey) throw Error('Azure Storage accountKey not found');
// Create credential
const sharedKeyCredential: StorageSharedKeyCredential =
new StorageSharedKeyCredential(accountName, accountKey);
const baseUrl = `https://${accountName}.blob.core.chinacloudapi.cn`;
const containerName = `my-container`;
const blobName = `my-blob`;
const fileContentsAsString = 'Hello there.';
async function main(): Promise<void> {
try {
// create blob from BlockBlobClient
const blockBlobClient = new BlockBlobClient(
`${baseUrl}/${containerName}/${blobName}`,
sharedKeyCredential
);
// Upload data to the blob
const blockBlobUploadResponse: BlockBlobUploadHeaders =
await blockBlobClient.upload(
fileContentsAsString,
fileContentsAsString.length
);
if (blockBlobUploadResponse.errorCode)
throw Error(blockBlobUploadResponse.errorCode);
console.log(`blob ${blockBlobClient.url} created`);
} catch (err) {
console.log(err);
throw err;
}
}
main()
.then(() => console.log(`success`))
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
Important
The account access key should be used with caution. If your account access key is lost or accidentally placed in an insecure location, your service may become vulnerable. Anyone who has the access key is able to authorize requests against the storage account, and effectively has access to all the data. DefaultAzureCredential provides enhanced security features and benefits and is the recommended approach for managing authorization to Azure services.
/**
* Best practice - use managed identity to avoid keys & connection strings
* managed identity is implemented with @azure/identity's DefaultAzureCredential
*
* The identity that the managed identity chain selects must have the
* correct roles applied in order to work correctly.
*
* For local development: add your personal identity on your resource group
* az role assignment create --assignee "<your-username>" \
* --role "Blob Data Contributor" \
* --resource-group "<your-resource-group-name>"
**/
//const logger = require('@azure/logger');
//logger.setLogLevel('info');
//<Snippet_Dependencies>
import {
BlobSASPermissions,
BlobSASSignatureValues,
BlobServiceClient,
BlockBlobClient,
BlockBlobUploadHeaders,
BlockBlobUploadResponse,
generateBlobSASQueryParameters,
SASProtocol,
SASQueryParameters,
ServiceGetUserDelegationKeyResponse
} from '@azure/storage-blob';
// used for local environment variables
import * as dotenv from 'dotenv';
dotenv.config();
// Get BlobServiceClient
import { getBlobServiceClientFromDefaultAzureCredential } from './auth-get-client';
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
const blobServiceClient: BlobServiceClient =
getBlobServiceClientFromDefaultAzureCredential();
//</Snippet_Dependencies>
//<Snippet_CreateBlobSas>
// Server creates User Delegation SAS Token for blob
async function createBlobSas(
blobServiceClient: BlobServiceClient,
blobName: string
): Promise<string> {
const containerName = 'my-container';
// Best practice: create time limits
const TEN_MINUTES = 10 * 60 * 1000;
const NOW = new Date();
// Best practice: set start time a little before current time to
// make sure any clock issues are avoided
const TEN_MINUTES_BEFORE_NOW = new Date(NOW.valueOf() - TEN_MINUTES);
const TEN_MINUTES_AFTER_NOW = new Date(NOW.valueOf() + TEN_MINUTES);
// Best practice: delegation key is time-limited
// When using a user delegation key, container must already exist
const userDelegationKey: ServiceGetUserDelegationKeyResponse =
await blobServiceClient.getUserDelegationKey(
TEN_MINUTES_BEFORE_NOW,
TEN_MINUTES_AFTER_NOW
);
if (userDelegationKey.errorCode) throw Error(userDelegationKey.errorCode);
// Need only create/write permission to upload file
const blobPermissionsForAnonymousUser = 'cw';
// Best practice: SAS options are time-limited
const sasOptions: BlobSASSignatureValues = {
blobName,
containerName,
permissions: BlobSASPermissions.parse(blobPermissionsForAnonymousUser),
protocol: SASProtocol.HttpsAndHttp,
startsOn: TEN_MINUTES_BEFORE_NOW,
expiresOn: TEN_MINUTES_AFTER_NOW
};
const sasQueryParameters: SASQueryParameters = generateBlobSASQueryParameters(
sasOptions,
userDelegationKey,
accountName
);
const sasToken: string = sasQueryParameters.toString();
return sasToken;
}
//</Snippet_CreateBlobSas>
//<Snippet_UploadToBlob>
// Client or another process uses SAS token to upload content to blob
async function uploadStringToBlob(
blobName: string,
sasToken,
textAsString: string
): Promise<BlockBlobUploadHeaders> {
// Get environment variables
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME as string;
const containerName = 'my-container';
// Create Url SAS token as query string with typical `?` delimiter
const sasUrl = `https://${accountName}.blob.core.chinacloudapi.cn/${containerName}/${blobName}?${sasToken}`;
console.log(`\nBlobUrl = ${sasUrl}\n`);
// Create blob client from SAS token url
const blockBlobClient = new BlockBlobClient(sasUrl);
// Upload string
const blockBlobUploadResponse: BlockBlobUploadHeaders =
await blockBlobClient.upload(textAsString, textAsString.length, undefined);
if (blockBlobUploadResponse.errorCode)
throw Error(blockBlobUploadResponse.errorCode);
return blockBlobUploadResponse;
}
//</Snippet_UploadToBlob>
//<Snippet_Main>
async function main(blobServiceClient: BlobServiceClient) {
// Create random blob name for text file
const blobName = `${(0 | (Math.random() * 9e6)).toString(36)}.txt`;
// Server creates SAS Token
const userDelegationSasForBlob: string = await createBlobSas(
blobServiceClient,
blobName
);
// Server hands off SAS Token & blobName to client to
// Upload content
const result: BlockBlobUploadHeaders = await uploadStringToBlob(
blobName,
userDelegationSasForBlob,
'Hello Blob World'
);
if (result.errorCode) throw Error(result.errorCode);
console.log(`\n${blobName} uploaded successfully ${result.lastModified}\n`);
}
main(blobServiceClient)
.then(() => {
console.log(`success`);
})
.catch((err: unknown) => {
if (err instanceof Error) {
console.log(err.message);
}
});
//</Snippet_Main>
Note
For scenarios where shared access signatures (SAS) are used, Azure recommends using a user delegation SAS. A user delegation SAS is secured with Microsoft Entra credentials instead of the account key. To learn more, see Create a user delegation SAS with JavaScript.
The dotenv package is used to read your storage account name from a .env file. This file should not be checked into source control.