Azure Keyvault Secrets 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
This skill provides guidance and code patterns for integrating the @azure/keyvault-secrets and @azure/keyvault-keys SDKs into Node.js applications. It covers the full lifecycle of secrets and cryptographic keys, including creation, retrieval, rotation, and deletion, as well as performing cryptographic operations like encryption, decryption, signing, and verification.
What it does
- Initializes SecretClient and KeyClient for Azure Key Vault interaction
- Performs CRUD operations on secrets and cryptographic keys
- Executes cryptographic functions including encryption, decryption, signing, and verification
- Manages key rotation policies and manual key rotation
- Handles backup and restoration of secrets and keys
- Provides patterns for soft-delete, recovery, and purging of vault items
When to use it
- When integrating Azure Key Vault into a Node.js application
- When managing application configuration values or sensitive credentials
- When implementing cryptographic operations backed by hardware security modules
- When automating key rotation or lifecycle management for security assets
Advantages
- Official Microsoft SDK integration for Node.js
- Supports granular control over secret and key attributes
- Includes built-in support for cryptographic operations
- Provides clear patterns for authentication using Azure Identity
Usage examples
- “How do I retrieve a secret from Azure Key Vault in my Node.js app?”
- The agent provides the code to initialize a SecretClient using DefaultAzureCredential and demonstrates the getSecret method to fetch the latest version of a specific secret.
- “Show me how to encrypt data using a key stored in Azure Key Vault.”
- The agent explains how to initialize a CryptographyClient with a key ID and demonstrates the encrypt method using a specified algorithm.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/microsoft/azure-keyvault-secrets-ts/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip azure-keyvault-secrets-ts.zip -d .agents/skills
Documentation by Microsoft
Azure Key Vault Secrets SDK for TypeScript
Manage secrets with Azure Key Vault.
Installation
# Secrets SDK
npm install @azure/keyvault-secrets @azure/identityEnvironment Variables
KEY_VAULT_URL=https://<vault-name>.vault.azure.net
# Or
AZURE_KEYVAULT_NAME=<vault-name>
AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in productionAuthentication
import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";
import { SecretClient } from "@azure/keyvault-secrets";
// 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 vaultUrl = `https://${process.env.AZURE_KEYVAULT_NAME}.vault.azure.net`;
const keyClient = new KeyClient(vaultUrl, credential);
const secretClient = new SecretClient(vaultUrl, credential);Secrets Operations
Create/Set Secret
const secret = await secretClient.setSecret("MySecret", "secret-value");
// With attributes
const secretWithAttrs = await secretClient.setSecret("MySecret", "value", {
enabled: true,
expiresOn: new Date("2025-12-31"),
contentType: "application/json",
tags: { environment: "production" }
});Get Secret
// Get latest version
const secret = await secretClient.getSecret("MySecret");
console.log(secret.value);
// Get specific version
const specificSecret = await secretClient.getSecret("MySecret", {
version: secret.properties.version
});List Secrets
for await (const secretProperties of secretClient.listPropertiesOfSecrets()) {
console.log(secretProperties.name);
}
// List versions
for await (const version of secretClient.listPropertiesOfSecretVersions("MySecret")) {
console.log(version.version);
}Delete Secret
// Soft delete
const deletePoller = await secretClient.beginDeleteSecret("MySecret");
await deletePoller.pollUntilDone();
// Purge (permanent)
await secretClient.purgeDeletedSecret("MySecret");
// Recover
const recoverPoller = await secretClient.beginRecoverDeletedSecret("MySecret");
await recoverPoller.pollUntilDone();Keys Operations
Create Keys
// Generic key
const key = await keyClient.createKey("MyKey", "RSA");
// RSA key with size
const rsaKey = await keyClient.createRsaKey("MyRsaKey", { keySize: 2048 });
// Elliptic Curve key
const ecKey = await keyClient.createEcKey("MyEcKey", { curve: "P-256" });
// With attributes
const keyWithAttrs = await keyClient.createKey("MyKey", "RSA", {
enabled: true,
expiresOn: new Date("2025-12-31"),
tags: { purpose: "encryption" },
keyOps: ["encrypt", "decrypt", "sign", "verify"]
});Get Key
const key = await keyClient.getKey("MyKey");
console.log(key.name, key.keyType);List Keys
for await (const keyProperties of keyClient.listPropertiesOfKeys()) {
console.log(keyProperties.name);
}Rotate Key
// Manual rotation
const rotatedKey = await keyClient.rotateKey("MyKey");
// Set rotation policy
await keyClient.updateKeyRotationPolicy("MyKey", {
lifetimeActions: [{ action: "Rotate", timeBeforeExpiry: "P30D" }],
expiresIn: "P90D"
});Delete Key
const deletePoller = await keyClient.beginDeleteKey("MyKey");
await deletePoller.pollUntilDone();
// Purge
await keyClient.purgeDeletedKey("MyKey");Cryptographic Operations
Create CryptographyClient
import { CryptographyClient } from "@azure/keyvault-keys";
// From key object
const cryptoClient = new CryptographyClient(key, credential);
// From key ID
const cryptoClient = new CryptographyClient(key.id!, credential);Encrypt/Decrypt
// Encrypt
const encryptResult = await cryptoClient.encrypt({
algorithm: "RSA-OAEP",
plaintext: Buffer.from("My secret message")
});
// Decrypt
const decryptResult = await cryptoClient.decrypt({
algorithm: "RSA-OAEP",
ciphertext: encryptResult.result
});
console.log(decryptResult.result.toString());Sign/Verify
import { createHash } from "node:crypto";
// Create digest
const hash = createHash("sha256").update("My message").digest();
// Sign
const signResult = await cryptoClient.sign("RS256", hash);
// Verify
const verifyResult = await cryptoClient.verify("RS256", hash, signResult.result);
console.log("Valid:", verifyResult.result);Wrap/Unwrap Keys
// Wrap a key (encrypt it for storage)
const wrapResult = await cryptoClient.wrapKey("RSA-OAEP", Buffer.from("key-material"));
// Unwrap
const unwrapResult = await cryptoClient.unwrapKey("RSA-OAEP", wrapResult.result);Backup and Restore
// Backup
const keyBackup = await keyClient.backupKey("MyKey");
const secretBackup = await secretClient.backupSecret("MySecret");
// Restore (can restore to different vault)
const restoredKey = await keyClient.restoreKeyBackup(keyBackup!);
const restoredSecret = await secretClient.restoreSecretBackup(secretBackup!);Key Types
import {
KeyClient,
KeyVaultKey,
KeyProperties,
DeletedKey,
CryptographyClient,
KnownEncryptionAlgorithms,
KnownSignatureAlgorithms
} from "@azure/keyvault-keys";
import {
SecretClient,
KeyVaultSecret,
SecretProperties,
DeletedSecret
} from "@azure/keyvault-secrets";Error Handling
try {
const secret = await secretClient.getSecret("NonExistent");
} catch (error: any) {
if (error.code === "SecretNotFound") {
console.log("Secret does not exist");
} else {
throw error;
}
}Best Practices
Use
DefaultAzureCredentialfor local development; useManagedIdentityCredentialorWorkloadIdentityCredentialfor productionEnable soft-delete - Required for production vaults
Set expiration dates - On both keys and secrets
Use key rotation policies - Automate key rotation
Limit key operations - Only grant needed operations (encrypt, sign, etc.)
Browser not supported - These SDKs are Node.js only
Files
- ATTRIBUTION.mdAdded by AutoGineer994 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md6.6 KiB
- references/keys.md11.8 KiB
- references/secrets.md13.3 KiB
references/secrets.md
Secrets Reference
Secret management operations using @azure/keyvault-secrets SDK.
Overview
The SecretClient provides operations for managing secrets in Azure Key Vault:
Create, update, and delete secrets
List secrets and versions
Soft-delete and purge operations
Backup and restore capabilities
Core Types
import {
SecretClient,
KeyVaultSecret,
SecretProperties,
DeletedSecret,
SetSecretOptions,
GetSecretOptions,
UpdateSecretPropertiesOptions,
BeginDeleteSecretOptions,
BeginRecoverDeletedSecretOptions,
ListPropertiesOfSecretsOptions,
ListPropertiesOfSecretVersionsOptions,
ListDeletedSecretsOptions
} from "@azure/keyvault-secrets";SecretClient Initialization
import { SecretClient } from "@azure/keyvault-secrets";
import { DefaultAzureCredential } from "@azure/identity";
const vaultUrl = `https://${process.env.AZURE_KEYVAULT_NAME}.vault.azure.net`;
const credential = new DefaultAzureCredential();
const secretClient = new SecretClient(vaultUrl, credential);Creating and Updating Secrets
Set Secret (Create or Update)
// Basic secret
const secret = await secretClient.setSecret("MySecret", "secret-value");
console.log(`Secret: ${secret.name}, Version: ${secret.properties.version}`);
// Secret with options
const secretWithOptions = await secretClient.setSecret("MySecret", "secret-value", {
enabled: true,
expiresOn: new Date("2025-12-31"),
notBefore: new Date("2024-01-01"),
contentType: "text/plain",
tags: {
environment: "production",
application: "my-app",
owner: "team-a"
}
});Content Types
// JSON content
const jsonSecret = await secretClient.setSecret(
"config-secret",
JSON.stringify({ apiKey: "xyz", endpoint: "https://api.example.com" }),
{ contentType: "application/json" }
);
// Connection string
const connString = await secretClient.setSecret(
"db-connection",
"Server=tcp:myserver.database.windows.net;Database=mydb;...",
{ contentType: "text/plain; charset=utf-8" }
);
// Base64 encoded binary
const binarySecret = await secretClient.setSecret(
"certificate-data",
Buffer.from(certificateBytes).toString("base64"),
{ contentType: "application/x-pkcs12" }
);Versioning Behavior
// Each setSecret creates a new version
const v1 = await secretClient.setSecret("MySecret", "value-1");
console.log(`Version 1: ${v1.properties.version}`);
const v2 = await secretClient.setSecret("MySecret", "value-2");
console.log(`Version 2: ${v2.properties.version}`);
// v1 still exists and is accessible by version ID
const v1Retrieved = await secretClient.getSecret("MySecret", {
version: v1.properties.version
});Retrieving Secrets
Get Secret
// Get latest version
const secret = await secretClient.getSecret("MySecret");
console.log(`Value: ${secret.value}`);
console.log(`Version: ${secret.properties.version}`);
console.log(`Created: ${secret.properties.createdOn}`);
// Get specific version
const specificVersion = await secretClient.getSecret("MySecret", {
version: "abc123def456..."
});KeyVaultSecret Structure
interface KeyVaultSecret {
name: string;
value?: string; // Only present when retrieved, not in list operations
properties: SecretProperties;
}
interface SecretProperties {
id?: string; // Full secret identifier URL
name: string;
version?: string;
vaultUrl: string;
enabled?: boolean;
notBefore?: Date;
expiresOn?: Date;
createdOn?: Date;
updatedOn?: Date;
contentType?: string;
tags?: { [key: string]: string };
managed?: boolean; // True if managed by Key Vault (e.g., storage account keys)
recoverableDays?: number;
recoveryLevel?: string;
}Listing Secrets
List All Secrets
// List secret properties (not values - use getSecret for values)
for await (const secretProperties of secretClient.listPropertiesOfSecrets()) {
console.log(`Secret: ${secretProperties.name}`);
console.log(` Enabled: ${secretProperties.enabled}`);
console.log(` Content Type: ${secretProperties.contentType}`);
console.log(` Tags: ${JSON.stringify(secretProperties.tags)}`);
}List Secret Versions
// List all versions of a specific secret
for await (const version of secretClient.listPropertiesOfSecretVersions("MySecret")) {
console.log(`Version: ${version.version}`);
console.log(` Created: ${version.createdOn}`);
console.log(` Enabled: ${version.enabled}`);
console.log(` Expires: ${version.expiresOn}`);
}Collect to Array
// Collect all secrets to array
const allSecrets: SecretProperties[] = [];
for await (const secret of secretClient.listPropertiesOfSecrets()) {
allSecrets.push(secret);
}
// Or use byPage for pagination control
const pages = secretClient.listPropertiesOfSecrets().byPage({ maxPageSize: 25 });
for await (const page of pages) {
console.log(`Page with ${page.length} secrets`);
}Filter by Tags
// SDK doesn't support server-side filtering, filter client-side
const productionSecrets: SecretProperties[] = [];
for await (const secret of secretClient.listPropertiesOfSecrets()) {
if (secret.tags?.environment === "production") {
productionSecrets.push(secret);
}
}Updating Secret Properties
// Update properties without changing value
const updated = await secretClient.updateSecretProperties("MySecret", "version-id", {
enabled: false,
expiresOn: new Date("2026-12-31"),
tags: { status: "deprecated", deprecatedOn: new Date().toISOString() }
});
// Update latest version (get version first)
const current = await secretClient.getSecret("MySecret");
await secretClient.updateSecretProperties("MySecret", current.properties.version!, {
enabled: true
});Soft Delete Operations
Delete Secret
// Begin delete (long-running operation)
const deletePoller = await secretClient.beginDeleteSecret("MySecret");
// Option 1: Wait for completion
const deletedSecret = await deletePoller.pollUntilDone();
console.log(`Deleted: ${deletedSecret.name}`);
console.log(`Scheduled purge: ${deletedSecret.scheduledPurgeDate}`);
console.log(`Deleted on: ${deletedSecret.deletedOn}`);
// Option 2: Non-blocking with periodic checks
const poller = await secretClient.beginDeleteSecret("MySecret");
while (!poller.isDone()) {
await poller.poll();
const state = poller.getOperationState();
console.log(`Delete status: ${state.isStarted ? "in progress" : "pending"}`);
await new Promise(resolve => setTimeout(resolve, 2000));
}Get Deleted Secret
// Get info about a deleted secret
const deleted = await secretClient.getDeletedSecret("MySecret");
console.log(`Recovery ID: ${deleted.recoveryId}`);
console.log(`Scheduled purge: ${deleted.scheduledPurgeDate}`);List Deleted Secrets
// List all deleted secrets in vault
for await (const deletedSecret of secretClient.listDeletedSecrets()) {
console.log(`Deleted secret: ${deletedSecret.name}`);
console.log(` Deleted on: ${deletedSecret.deletedOn}`);
console.log(` Purge date: ${deletedSecret.scheduledPurgeDate}`);
}Recover Deleted Secret
// Recover a soft-deleted secret
const recoverPoller = await secretClient.beginRecoverDeletedSecret("MySecret");
const recoveredSecret = await recoverPoller.pollUntilDone();
console.log(`Recovered: ${recoveredSecret.name}`);Purge Secret (Permanent Delete)
// Permanently delete - IRREVERSIBLE
// Requires "purge" permission in RBAC
await secretClient.purgeDeletedSecret("MySecret");
// Common pattern: delete then purge
const deletePoller = await secretClient.beginDeleteSecret("MySecret");
await deletePoller.pollUntilDone();
await secretClient.purgeDeletedSecret("MySecret");Backup and Restore
Backup Secret
// Backup returns encrypted blob containing all versions
const backup = await secretClient.backupSecret("MySecret");
if (backup) {
// Store backup securely (e.g., blob storage, local file)
console.log(`Backup size: ${backup.length} bytes`);
// Save to file
import { writeFileSync } from "node:fs";
writeFileSync("secret-backup.bin", backup);
}Restore Secret
import { readFileSync } from "node:fs";
// Read backup from storage
const backupData = readFileSync("secret-backup.bin");
// Restore to vault (can be different vault in same region/subscription)
const restoredSecret = await secretClient.restoreSecretBackup(backupData);
console.log(`Restored: ${restoredSecret.name}`);Backup Constraints
| Constraint | Description |
|---|---|
| Same subscription | Backup can only be restored to vault in same Azure subscription |
| Same geography | Target vault must be in same Azure geography |
| All versions | Backup includes all versions of the secret |
| Encrypted | Backup blob is encrypted with Microsoft-managed keys |
Error Handling
import { RestError } from "@azure/core-rest-pipeline";
async function getSecretSafely(name: string): Promise<KeyVaultSecret | null> {
try {
return await secretClient.getSecret(name);
} catch (error) {
if (error instanceof RestError) {
switch (error.statusCode) {
case 404:
console.log(`Secret '${name}' not found`);
return null;
case 403:
console.log("Access denied - check RBAC permissions");
throw error;
case 409:
console.log("Conflict - secret is being deleted or already exists");
throw error;
default:
console.log(`Error ${error.statusCode}: ${error.message}`);
throw error;
}
}
throw error;
}
}Common Error Codes
| Code | Meaning |
|---|---|
| 404 | Secret not found (or deleted) |
| 403 | Access denied (RBAC permission missing) |
| 409 | Conflict (secret exists in deleted state) |
| 429 | Rate limited (too many requests) |
Common Patterns
Secret Rotation
async function rotateSecret(name: string, newValue: string): Promise<KeyVaultSecret> {
// Get current secret to preserve metadata
const current = await secretClient.getSecret(name);
// Disable old version
await secretClient.updateSecretProperties(name, current.properties.version!, {
enabled: false,
tags: {
...current.properties.tags,
rotatedOn: new Date().toISOString(),
status: "rotated"
}
});
// Create new version with same settings
const newSecret = await secretClient.setSecret(name, newValue, {
enabled: true,
contentType: current.properties.contentType,
expiresOn: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000), // 90 days
tags: {
...current.properties.tags,
status: "active",
createdOn: new Date().toISOString()
}
});
return newSecret;
}Bulk Secret Operations
async function exportAllSecrets(): Promise<Map<string, string>> {
const secrets = new Map<string, string>();
for await (const properties of secretClient.listPropertiesOfSecrets()) {
if (properties.enabled) {
const secret = await secretClient.getSecret(properties.name);
if (secret.value) {
secrets.set(properties.name, secret.value);
}
}
}
return secrets;
}
async function importSecrets(secrets: Map<string, string>, tags?: Record<string, string>): Promise<void> {
for (const [name, value] of secrets) {
await secretClient.setSecret(name, value, { tags });
console.log(`Imported: ${name}`);
}
}Check Secret Expiration
async function getExpiringSecrets(daysThreshold: number = 30): Promise<SecretProperties[]> {
const expiringSecrets: SecretProperties[] = [];
const thresholdDate = new Date(Date.now() + daysThreshold * 24 * 60 * 60 * 1000);
for await (const secret of secretClient.listPropertiesOfSecrets()) {
if (secret.enabled && secret.expiresOn && secret.expiresOn <= thresholdDate) {
expiringSecrets.push(secret);
}
}
return expiringSecrets;
}Best Practices
Use managed identity - DefaultAzureCredential handles MI in Azure, dev credentials locally
Set expiration dates - Enforce secret rotation with
expiresOnUse content types - Helps consumers understand secret format
Tag secrets - Environment, application, owner for organization
Enable soft-delete - Required for production vaults (default for new vaults)
Enable purge protection - Prevents accidental permanent deletion
Backup before rotation - Backup secrets before making changes
Least privilege - Grant only needed permissions (Get vs List vs Set)
Monitor expiration - Alert on secrets expiring within threshold
Avoid storing in code - Use Key Vault references in App Service/Functions
RBAC Permissions
| Operation | Required Permission |
|---|---|
| Get secret | Microsoft.KeyVault/vaults/secrets/getSecret/action |
| List secrets | Microsoft.KeyVault/vaults/secrets/readMetadata/action |
| Set secret | Microsoft.KeyVault/vaults/secrets/setSecret/action |
| Delete secret | Microsoft.KeyVault/vaults/secrets/delete |
| Purge secret | Microsoft.KeyVault/vaults/secrets/purge/action |
| Backup | Microsoft.KeyVault/vaults/secrets/backup/action |
| Restore | Microsoft.KeyVault/vaults/secrets/restore/action |
See Also
keys.md - Cryptographic key management
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-keyvault-secrets-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.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download azure-keyvault-secrets-ts.zip