GitHub Copilot ChatGPT Claude Codex CLI Cursor opencode Skill Text

azure-keyvault-keys-ts

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

Ciza · 0 points · 22 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download microsoft-skills-.github_plugins_azure-sdk-typescript_skills_azure-keyvault-keys-ts-e58528d.zip · 10 KB
Part of microsoft/skills — 195 skills

Install

skills CLI npx skills add https://github.com/microsoft/skills/tree/main/.github/plugins/azure-sdk-typescript/skills/azure-keyvault-keys-ts
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install microsoft-skills@llmmart
Git git clone https://github.com/microsoft/skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole microsoft/skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

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 (skills)
  • references
    • keys.md 11.8 KB
      # Keys Reference
      
      Cryptographic key management and operations using @azure/keyvault-keys SDK.
      
      ## Overview
      
      The Key Vault Keys SDK provides two main clients:
      - **KeyClient** - CRUD operations for keys (create, get, list, rotate, delete)
      - **CryptographyClient** - Cryptographic operations using keys (encrypt, decrypt, sign, verify, wrap, unwrap)
      
      ## Core Types
      
      ```typescript
      import {
        KeyClient,
        CryptographyClient,
        KeyVaultKey,
        KeyProperties,
        DeletedKey,
        KeyRotationPolicy,
        KeyRotationPolicyProperties,
        KeyRotationLifetimeAction,
        CreateKeyOptions,
        CreateRsaKeyOptions,
        CreateEcKeyOptions,
        EncryptParameters,
        DecryptParameters,
        SignResult,
        VerifyResult,
        WrapResult,
        UnwrapResult,
        KnownEncryptionAlgorithms,
        KnownSignatureAlgorithms,
        KnownKeyTypes,
        KnownKeyCurveNames
      } from "@azure/keyvault-keys";
      ```
      
      ## KeyClient Initialization
      
      ```typescript
      import { KeyClient } from "@azure/keyvault-keys";
      import { DefaultAzureCredential } from "@azure/identity";
      
      const vaultUrl = `https://${process.env.AZURE_KEYVAULT_NAME}.vault.azure.net`;
      const credential = new DefaultAzureCredential();
      
      const keyClient = new KeyClient(vaultUrl, credential);
      ```
      
      ## Creating Keys
      
      ### RSA Keys
      
      ```typescript
      // Basic RSA key (default 2048-bit)
      const rsaKey = await keyClient.createRsaKey("my-rsa-key");
      
      // RSA key with specific size
      const rsaKey2048 = await keyClient.createRsaKey("my-rsa-2048", {
        keySize: 2048
      });
      
      const rsaKey4096 = await keyClient.createRsaKey("my-rsa-4096", {
        keySize: 4096
      });
      
      // RSA-HSM (Hardware Security Module backed)
      const rsaHsmKey = await keyClient.createRsaKey("my-rsa-hsm", {
        keySize: 2048,
        hsm: true  // Requires Premium vault
      });
      ```
      
      ### Elliptic Curve Keys
      
      ```typescript
      // P-256 curve (default)
      const ecKey = await keyClient.createEcKey("my-ec-key");
      
      // Specific curves
      const ecKeyP256 = await keyClient.createEcKey("my-ec-p256", {
        curve: "P-256"
      });
      
      const ecKeyP384 = await keyClient.createEcKey("my-ec-p384", {
        curve: "P-384"
      });
      
      const ecKeyP521 = await keyClient.createEcKey("my-ec-p521", {
        curve: "P-521"
      });
      
      // EC-HSM
      const ecHsmKey = await keyClient.createEcKey("my-ec-hsm", {
        curve: "P-256",
        hsm: true
      });
      ```
      
      ### Oct Keys (Symmetric)
      
      ```typescript
      // Symmetric key for wrap/unwrap operations
      const octKey = await keyClient.createOctKey("my-oct-key", {
        keySize: 256  // 128, 192, or 256 bits
      });
      
      // Oct-HSM
      const octHsmKey = await keyClient.createOctKey("my-oct-hsm", {
        keySize: 256,
        hsm: true
      });
      ```
      
      ### Generic Create with Options
      
      ```typescript
      const key = await keyClient.createKey("my-key", "RSA", {
        keySize: 2048,
        enabled: true,
        expiresOn: new Date("2025-12-31"),
        notBefore: new Date("2024-01-01"),
        tags: {
          environment: "production",
          application: "my-app"
        },
        keyOps: ["encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey"],
        exportable: false,
        releasePolicy: undefined  // For Managed HSM key release
      });
      ```
      
      ## Key Operations
      
      ### Get Key
      
      ```typescript
      // Get latest version
      const key = await keyClient.getKey("my-key");
      console.log(`Key: ${key.name}, Type: ${key.keyType}, ID: ${key.id}`);
      
      // Get specific version
      const keyVersion = await keyClient.getKey("my-key", {
        version: "abc123..."
      });
      ```
      
      ### List Keys
      
      ```typescript
      // List all keys (properties only, not key material)
      for await (const keyProperties of keyClient.listPropertiesOfKeys()) {
        console.log(`Key: ${keyProperties.name}, Created: ${keyProperties.createdOn}`);
      }
      
      // List all versions of a key
      for await (const version of keyClient.listPropertiesOfKeyVersions("my-key")) {
        console.log(`Version: ${version.version}, Enabled: ${version.enabled}`);
      }
      
      // List deleted keys (soft-delete enabled vaults)
      for await (const deletedKey of keyClient.listDeletedKeys()) {
        console.log(`Deleted: ${deletedKey.name}, Scheduled purge: ${deletedKey.scheduledPurgeDate}`);
      }
      ```
      
      ### Update Key Properties
      
      ```typescript
      const updated = await keyClient.updateKeyProperties("my-key", {
        enabled: false,
        expiresOn: new Date("2026-12-31"),
        tags: { status: "deprecated" }
      });
      
      // Update specific version
      const updatedVersion = await keyClient.updateKeyProperties("my-key", "version-id", {
        enabled: true
      });
      ```
      
      ### Import Key
      
      ```typescript
      import { JsonWebKey } from "@azure/keyvault-keys";
      
      // Import existing key material
      const jwk: JsonWebKey = {
        kty: "RSA",
        n: Buffer.from("...modulus..."),
        e: Buffer.from("...exponent..."),
        d: Buffer.from("...private exponent..."),  // Optional for public key
        // ... other RSA parameters
      };
      
      const importedKey = await keyClient.importKey("imported-key", jwk, {
        hardwareProtected: false  // true for HSM
      });
      ```
      
      ## Key Rotation
      
      ### Manual Rotation
      
      ```typescript
      // Creates new version, previous versions remain valid
      const rotatedKey = await keyClient.rotateKey("my-key");
      console.log(`New version: ${rotatedKey.properties.version}`);
      ```
      
      ### Rotation Policy
      
      ```typescript
      // Get current policy
      const policy = await keyClient.getKeyRotationPolicy("my-key");
      
      // Update rotation policy
      const updatedPolicy = await keyClient.updateKeyRotationPolicy("my-key", {
        expiresIn: "P90D",  // ISO 8601 duration - key expires 90 days after creation
        lifetimeActions: [
          {
            action: "Rotate",
            timeAfterCreate: "P30D"  // Auto-rotate 30 days after creation
          },
          {
            action: "Notify",
            timeBeforeExpiry: "P7D"  // Notify 7 days before expiry
          }
        ]
      });
      
      // Rotation policy with multiple actions
      const complexPolicy = await keyClient.updateKeyRotationPolicy("my-key", {
        expiresIn: "P1Y",  // 1 year
        lifetimeActions: [
          { action: "Rotate", timeAfterCreate: "P90D" },  // Rotate every 90 days
          { action: "Notify", timeBeforeExpiry: "P30D" }  // Notify 30 days before expiry
        ]
      });
      ```
      
      ### ISO 8601 Duration Format
      
      | Duration | Meaning |
      |----------|---------|
      | `P30D` | 30 days |
      | `P90D` | 90 days |
      | `P1Y` | 1 year |
      | `P6M` | 6 months |
      | `P1Y6M` | 1 year 6 months |
      
      ## Key Deletion and Recovery
      
      ### Soft Delete (Default)
      
      ```typescript
      // Begin delete (returns poller for long-running operation)
      const deletePoller = await keyClient.beginDeleteKey("my-key");
      
      // Wait for deletion to complete
      const deletedKey = await deletePoller.pollUntilDone();
      console.log(`Deleted: ${deletedKey.name}, Recovery ID: ${deletedKey.recoveryId}`);
      
      // Get deleted key info
      const deleted = await keyClient.getDeletedKey("my-key");
      
      // Recover deleted key
      const recoverPoller = await keyClient.beginRecoverDeletedKey("my-key");
      const recoveredKey = await recoverPoller.pollUntilDone();
      
      // Permanently delete (purge) - irreversible
      await keyClient.purgeDeletedKey("my-key");
      ```
      
      ### Immediate Deletion (Non-blocking)
      
      ```typescript
      // Start deletion without waiting
      const poller = await keyClient.beginDeleteKey("my-key");
      
      // Check status periodically
      while (!poller.isDone()) {
        await poller.poll();
        console.log(`State: ${poller.getOperationState().status}`);
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
      ```
      
      ## CryptographyClient
      
      ### Initialization
      
      ```typescript
      import { CryptographyClient } from "@azure/keyvault-keys";
      
      // From KeyVaultKey object
      const key = await keyClient.getKey("my-key");
      const cryptoClient = new CryptographyClient(key, credential);
      
      // From key ID (URL)
      const cryptoClientFromId = new CryptographyClient(
        "https://my-vault.vault.azure.net/keys/my-key/version",
        credential
      );
      
      // From key ID without version (uses latest)
      const cryptoClientLatest = new CryptographyClient(
        "https://my-vault.vault.azure.net/keys/my-key",
        credential
      );
      ```
      
      ### Encrypt / Decrypt
      
      ```typescript
      // RSA encryption
      const plaintext = Buffer.from("Secret message");
      
      // Encrypt with RSA-OAEP
      const encryptResult = await cryptoClient.encrypt({
        algorithm: "RSA-OAEP",
        plaintext
      });
      
      console.log(`Encrypted (${encryptResult.result.length} bytes)`);
      
      // Decrypt
      const decryptResult = await cryptoClient.decrypt({
        algorithm: "RSA-OAEP",
        ciphertext: encryptResult.result
      });
      
      console.log(`Decrypted: ${decryptResult.result.toString()}`);
      ```
      
      ### Encryption Algorithms
      
      | Algorithm | Key Type | Description |
      |-----------|----------|-------------|
      | `RSA1_5` | RSA | RSA with PKCS#1 v1.5 padding |
      | `RSA-OAEP` | RSA | RSA with OAEP padding (SHA-1) |
      | `RSA-OAEP-256` | RSA | RSA with OAEP padding (SHA-256) |
      | `A128GCM` | oct | AES-128-GCM |
      | `A192GCM` | oct | AES-192-GCM |
      | `A256GCM` | oct | AES-256-GCM |
      | `A128CBC` | oct | AES-128-CBC |
      | `A192CBC` | oct | AES-192-CBC |
      | `A256CBC` | oct | AES-256-CBC |
      
      ### Sign / Verify
      
      ```typescript
      import { createHash } from "node:crypto";
      
      // Create SHA-256 hash of data to sign
      const data = Buffer.from("Data to sign");
      const hash = createHash("sha256").update(data).digest();
      
      // Sign with RSA key
      const signResult = await cryptoClient.sign("RS256", hash);
      console.log(`Signature (${signResult.result.length} bytes)`);
      
      // Verify signature
      const verifyResult = await cryptoClient.verify("RS256", hash, signResult.result);
      console.log(`Valid: ${verifyResult.result}`);
      
      // Sign data directly (SDK computes hash)
      const signDataResult = await cryptoClient.signData("RS256", data);
      const verifyDataResult = await cryptoClient.verifyData("RS256", data, signDataResult.result);
      ```
      
      ### Signature Algorithms
      
      | Algorithm | Key Type | Hash | Description |
      |-----------|----------|------|-------------|
      | `RS256` | RSA | SHA-256 | RSASSA-PKCS1-v1_5 |
      | `RS384` | RSA | SHA-384 | RSASSA-PKCS1-v1_5 |
      | `RS512` | RSA | SHA-512 | RSASSA-PKCS1-v1_5 |
      | `PS256` | RSA | SHA-256 | RSASSA-PSS |
      | `PS384` | RSA | SHA-384 | RSASSA-PSS |
      | `PS512` | RSA | SHA-512 | RSASSA-PSS |
      | `ES256` | EC P-256 | SHA-256 | ECDSA |
      | `ES384` | EC P-384 | SHA-384 | ECDSA |
      | `ES512` | EC P-521 | SHA-512 | ECDSA |
      
      ### Wrap / Unwrap Keys
      
      ```typescript
      // Key encryption key (KEK) wraps another key
      const keyMaterial = Buffer.from("32-byte-key-material-here!!!!!");  // 32 bytes for AES-256
      
      // Wrap (encrypt) the key material
      const wrapResult = await cryptoClient.wrapKey("RSA-OAEP", keyMaterial);
      console.log(`Wrapped key (${wrapResult.result.length} bytes)`);
      
      // Unwrap (decrypt) the key material
      const unwrapResult = await cryptoClient.unwrapKey("RSA-OAEP", wrapResult.result);
      console.log(`Unwrapped: ${unwrapResult.result.length} bytes`);
      ```
      
      ## Backup and Restore
      
      ```typescript
      // Backup key (returns encrypted blob)
      const backup = await keyClient.backupKey("my-key");
      if (backup) {
        // Store backup securely (e.g., blob storage)
        console.log(`Backup size: ${backup.length} bytes`);
      }
      
      // Restore key (can restore to different vault in same region/subscription)
      const restoredKey = await keyClient.restoreKeyBackup(backup!);
      console.log(`Restored: ${restoredKey.name}`);
      ```
      
      ## Error Handling
      
      ```typescript
      import { RestError } from "@azure/core-rest-pipeline";
      
      try {
        const key = await keyClient.getKey("non-existent-key");
      } catch (error) {
        if (error instanceof RestError) {
          switch (error.statusCode) {
            case 404:
              console.log("Key not found");
              break;
            case 403:
              console.log("Access denied - check RBAC permissions");
              break;
            case 409:
              console.log("Conflict - key already exists or is being deleted");
              break;
            default:
              console.log(`Error ${error.statusCode}: ${error.message}`);
          }
        }
        throw error;
      }
      ```
      
      ## Best Practices
      
      1. **Use managed identity in production** - DefaultAzureCredential handles this automatically
      2. **Enable soft-delete and purge protection** - Required for production vaults
      3. **Set key expiration** - Use `expiresOn` to enforce key lifecycle
      4. **Use rotation policies** - Automate key rotation for security compliance
      5. **Limit key operations** - Only grant needed operations (`keyOps`)
      6. **Use HSM for sensitive keys** - Hardware protection for critical cryptographic material
      7. **Backup keys before deletion** - Soft-delete has retention limits
      8. **Use specific key versions** - Pin to versions in production for stability
      
      ## See Also
      
      - [secrets.md](./secrets.md) - Secret management operations
      
    • secrets.md 13.3 KB
      # 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
      
      ```typescript
      import {
        SecretClient,
        KeyVaultSecret,
        SecretProperties,
        DeletedSecret,
        SetSecretOptions,
        GetSecretOptions,
        UpdateSecretPropertiesOptions,
        BeginDeleteSecretOptions,
        BeginRecoverDeletedSecretOptions,
        ListPropertiesOfSecretsOptions,
        ListPropertiesOfSecretVersionsOptions,
        ListDeletedSecretsOptions
      } from "@azure/keyvault-secrets";
      ```
      
      ## SecretClient Initialization
      
      ```typescript
      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)
      
      ```typescript
      // 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
      
      ```typescript
      // 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
      
      ```typescript
      // 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
      
      ```typescript
      // 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
      
      ```typescript
      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
      
      ```typescript
      // 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
      
      ```typescript
      // 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
      
      ```typescript
      // 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
      
      ```typescript
      // 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
      
      ```typescript
      // 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
      
      ```typescript
      // 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
      
      ```typescript
      // 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
      
      ```typescript
      // 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
      
      ```typescript
      // 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)
      
      ```typescript
      // 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
      
      ```typescript
      // 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
      
      ```typescript
      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
      
      ```typescript
      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
      
      ```typescript
      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
      
      ```typescript
      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
      
      ```typescript
      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
      
      | 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](./keys.md) - Cryptographic key management
      
  • SKILL.md 6.6 KB
    ---
    name: azure-keyvault-keys-ts
    description: Manage cryptographic keys using Azure Key Vault Keys SDK for JavaScript (@azure/keyvault-keys). Use when creating, encrypting/decrypting, signing, or rotating keys.
    license: MIT
    metadata:
      author: Microsoft
      version: "1.0.0"
      package: '@azure/keyvault-keys'
    ---
    
    # Azure Key Vault Keys SDK for TypeScript
    
    Manage cryptographic keys with Azure Key Vault.
    
    ## Installation
    
    ```bash
    # Keys SDK
    npm install @azure/keyvault-keys @azure/identity
    ```
    
    ## Environment Variables
    
    ```bash
    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
    
    ```typescript
    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
    
    ```typescript
    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
    
    ```typescript
    // 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
    
    ```typescript
    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
    
    ```typescript
    // 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
    
    ```typescript
    // 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
    
    ```typescript
    const key = await keyClient.getKey("MyKey");
    console.log(key.name, key.keyType);
    ```
    
    ### List Keys
    
    ```typescript
    for await (const keyProperties of keyClient.listPropertiesOfKeys()) {
      console.log(keyProperties.name);
    }
    ```
    
    ### Rotate Key
    
    ```typescript
    // Manual rotation
    const rotatedKey = await keyClient.rotateKey("MyKey");
    
    // Set rotation policy
    await keyClient.updateKeyRotationPolicy("MyKey", {
      lifetimeActions: [{ action: "Rotate", timeBeforeExpiry: "P30D" }],
      expiresIn: "P90D"
    });
    ```
    
    ### Delete Key
    
    ```typescript
    const deletePoller = await keyClient.beginDeleteKey("MyKey");
    await deletePoller.pollUntilDone();
    
    // Purge
    await keyClient.purgeDeletedKey("MyKey");
    ```
    
    ## Cryptographic Operations
    
    ### Create CryptographyClient
    
    ```typescript
    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
    
    ```typescript
    // 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
    
    ```typescript
    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
    
    ```typescript
    // 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
    
    ```typescript
    // 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
    
    ```typescript
    import {
      KeyClient,
      KeyVaultKey,
      KeyProperties,
      DeletedKey,
      CryptographyClient,
      KnownEncryptionAlgorithms,
      KnownSignatureAlgorithms
    } from "@azure/keyvault-keys";
    
    import {
      SecretClient,
      KeyVaultSecret,
      SecretProperties,
      DeletedSecret
    } from "@azure/keyvault-secrets";
    ```
    
    ## Error Handling
    
    ```typescript
    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
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related