Node.js Client for HashiCorp Vault
node-vault is a JavaScript client library for interacting with HashiCorp's Vault HTTP API, primarily designed for Node.js environments. The current stable version is 0.12.0, requiring Node.js 18.0.0 or higher. The project demonstrates a consistent release cadence with several minor and patch releases in the past year, indicating active maintenance. It provides a comprehensive wrapper around the Vault API, simplifying operations such as secret management (read, write, update, delete, list), authentication (e.g., Kubernetes Auth, token-based), and server lifecycle management (init, unseal). A key differentiator is its direct support for TypeScript with included definitions and its focus on being a reliable, actively developed client for Node.js users needing to integrate with Vault. It also allows configuration via environment variables for common Vault settings.
Common errors
-
Error: self-signed certificate in certificate chain
cause Connecting to a Vault instance (often local development setups) that uses a self-signed SSL certificate without Node.js trusting it.fixFor development, set the `VAULT_SKIP_VERIFY=true` environment variable (NOT recommended for production). For production, ensure your Vault instance uses a trusted certificate and your Node.js environment is configured to trust the issuing CA. -
Vault Error: permission denied
cause The Vault token provided to the client lacks the necessary capabilities (policies) to perform the requested operation on the specified path.fixVerify the Vault token being used has the appropriate policies attached. Use `vault token capabilities <token> <path>` or check Vault audit logs to debug policy issues. -
TypeError: vault.read is not a function
cause The `node-vault` module was imported incorrectly, typically by not calling the default exported function to instantiate a client object (e.g., `const vault = require('node-vault');` instead of `const vaultClient = require('node-vault')();`).fixEnsure you call the imported `node-vault` function to get a client instance: `const vaultClient = require('node-vault')({ /* options */ });` or `import createVaultClient from 'node-vault'; const vaultClient = createVaultClient({ /* options */ });` -
Error: connect ECONNREFUSED 127.0.0.1:8200
cause The `node-vault` client could not connect to the specified Vault server endpoint. This often means Vault is not running or is listening on a different address/port.fixVerify that your Vault server is running and accessible at the configured `endpoint` (or `VAULT_ADDR` environment variable). Check Vault's listener configuration.
Warnings
- breaking Versions of `node-vault` prior to `v0.11.0` (specifically `<= v0.10.0`) are compatible with older Node.js versions (>= 6.x), but these older client versions contain multiple known security vulnerabilities. It is strongly recommended to upgrade to Node.js 18+ and `node-vault >= v0.11.0`.
- gotcha The `endpoint` URL option (or `VAULT_ADDR` environment variable) should not contain a trailing slash. The client automatically strips trailing slashes to prevent malformed request URIs, which can lead to unexpected 404s or incorrect path resolution if you try to manually compensate.
- gotcha The `update` method performs an HTTP `PATCH` request with the `application/merge-patch+json` content type. This differs from a full `PUT` and applies partial updates. For KV2 secrets, this typically means merging `data` fields. Ensure your Vault policies and expectations align with a merge-patch operation.
- gotcha Disabling SSL certificate verification via `VAULT_SKIP_VERIFY` environment variable or client `requestOptions` for `httpsAgent` should be avoided in production environments due to severe security implications. This can lead to man-in-the-middle attacks.
Install
-
npm install node-vault -
yarn add node-vault -
pnpm add node-vault
Imports
- vault
import { vault } from 'node-vault';import vault from 'node-vault';
- vault
const { vault } = require('node-vault');const vault = require('node-vault'); - ClientOptions
import { ClientOptions } from 'node-vault';import type { ClientOptions } from 'node-vault';
Quickstart
import vault from 'node-vault';
async function runVaultOperations() {
const vaultClient = vault({
apiVersion: 'v1',
endpoint: process.env.VAULT_ADDR ?? 'http://127.0.0.1:8200',
token: process.env.VAULT_TOKEN ?? '', // Recommended to use VAULT_TOKEN env var for actual usage
});
if (!vaultClient.token) {
console.warn("VAULT_TOKEN environment variable not set. Operations requiring authentication will likely fail.");
}
const secretPath = 'secret/data/my-app/config';
const dataToWrite = {
value: 'super-secret-data-' + Date.now(),
environment: 'development'
};
try {
console.log(`Writing secret to ${secretPath}...`);
await vaultClient.write(secretPath, { data: dataToWrite });
console.log('Secret written successfully.');
console.log(`Reading secret from ${secretPath}...`);
const result = await vaultClient.read(secretPath);
console.log('Secret read:', result.data.data);
console.log('Listing secrets in secret/metadata/my-app/');
const listResult = await vaultClient.list('secret/metadata/my-app/');
console.log('Listed keys:', listResult.data.keys);
console.log(`Updating secret at ${secretPath}...`);
await vaultClient.update(secretPath, { data: { updatedField: 'newValue' } });
console.log('Secret updated successfully.');
console.log(`Deleting secret at ${secretPath}...`);
await vaultClient.delete(secretPath);
console.log('Secret deleted successfully.');
} catch (error: any) {
console.error('Vault operation failed:', error.message);
if (error.response?.data) {
console.error('Vault API Error Details:', error.response.data);
}
if (error.message.includes('permission denied')) {
console.error('Ensure your Vault token has appropriate policies (read, write, list, delete) for secret/data/my-app/.');
}
}
}
runVaultOperations();