Generated banner for Azure Keyvault Keys TS
Generated logo for Azure Keyvault Keys TS

Azure Keyvault Keys TS

MicrosoftOfficialCreated by Microsoft

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

From the author

Manage cryptographic keys using Azure Key Vault Keys SDK for JavaScript (@azure/keyvault-keys). Use when creating, encrypting/decrypting, signing, or rotating keys.
— the description by Microsoft

AutoGineer summary

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

This skill provides a comprehensive guide to using the @azure/keyvault-keys and @azure/keyvault-secrets SDKs for Node.js. It covers the full lifecycle of cryptographic keys and secrets, including creation, retrieval, rotation, and deletion. The skill also details how to perform cryptographic operations like encryption, decryption, signing, and verification using the CryptographyClient, as well as best practices for authentication and security in Azure environments.

What it does

  • Initializes KeyClient and SecretClient for Azure Key Vault interaction.
  • Creates and manages RSA, Elliptic Curve, and symmetric keys.
  • Performs cryptographic operations including encryption, decryption, signing, and verification.
  • Handles secret lifecycle management including setting, retrieving, and versioning.
  • Configures key rotation policies and manual rotation.
  • Supports backup and restoration of keys and secrets.

When to use it

  • When you need to integrate Azure Key Vault into a Node.js application.
  • When you require secure storage for application secrets or connection strings.
  • When your application needs to perform cryptographic operations without exposing raw keys.
  • When you need to automate key rotation or manage key lifecycle policies.

Advantages

  • Provides native TypeScript support for Azure Key Vault operations.
  • Simplifies complex cryptographic tasks through the CryptographyClient.
  • Integrates seamlessly with Azure Identity for secure authentication.
  • Supports advanced features like HSM-backed keys and soft-delete recovery.

Usage examples

“How do I create a new RSA key in Azure Key Vault using the TypeScript SDK?”
The agent provides the code snippet using keyClient.createRsaKey, including options for key size and attributes.
“Show me how to encrypt a message using a key stored in Azure Key Vault.”
The agent demonstrates initializing a CryptographyClient with a key ID and calling the encrypt method with the desired algorithm.
“How can I set a secret in Azure Key Vault with an expiration date?”
The agent provides an example using secretClient.setSecret with an options object containing the expiresOn property.
“What is the best way to authenticate my Node.js app to Key Vault?”
The agent explains using DefaultAzureCredential for local development and ManagedIdentityCredential for production environments.

Install

  1. Download the skill as a ZIP:

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

    mkdir -p .agents/skills && unzip azure-keyvault-keys-ts.zip -d .agents/skills

Documentation by Microsoft

Azure Key Vault Keys SDK for TypeScript

Manage cryptographic keys with Azure Key Vault.

Installation

# Keys SDK
npm install @azure/keyvault-keys @azure/identity

Environment 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 production

Authentication

import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";
import { KeyClient, CryptographyClient } from "@azure/keyvault-keys";

// 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

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

  2. Enable soft-delete - Required for production vaults

  3. Set expiration dates - On both keys and secrets

  4. Use key rotation policies - Automate key rotation

  5. Limit key operations - Only grant needed operations (encrypt, sign, etc.)

  6. Browser not supported - These SDKs are Node.js only

Files

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
ConstraintDescription
Same subscriptionBackup can only be restored to vault in same Azure subscription
Same geographyTarget vault must be in same Azure geography
All versionsBackup includes all versions of the secret
EncryptedBackup 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
CodeMeaning
404Secret not found (or deleted)
403Access denied (RBAC permission missing)
409Conflict (secret exists in deleted state)
429Rate 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

  1. Use managed identity - DefaultAzureCredential handles MI in Azure, dev credentials locally

  2. Set expiration dates - Enforce secret rotation with expiresOn

  3. Use content types - Helps consumers understand secret format

  4. Tag secrets - Environment, application, owner for organization

  5. Enable soft-delete - Required for production vaults (default for new vaults)

  6. Enable purge protection - Prevents accidental permanent deletion

  7. Backup before rotation - Backup secrets before making changes

  8. Least privilege - Grant only needed permissions (Get vs List vs Set)

  9. Monitor expiration - Alert on secrets expiring within threshold

  10. Avoid storing in code - Use Key Vault references in App Service/Functions

RBAC Permissions

OperationRequired Permission
Get secretMicrosoft.KeyVault/vaults/secrets/getSecret/action
List secretsMicrosoft.KeyVault/vaults/secrets/readMetadata/action
Set secretMicrosoft.KeyVault/vaults/secrets/setSecret/action
Delete secretMicrosoft.KeyVault/vaults/secrets/delete
Purge secretMicrosoft.KeyVault/vaults/secrets/purge/action
BackupMicrosoft.KeyVault/vaults/secrets/backup/action
RestoreMicrosoft.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-keys-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-keyvault-keys-ts.zip