A client for the HTTP API of HashiCorp's Vault written for Node.js.
Prerequisites:
- Node.js >=
18.0.0
npm install -S node-vaultNote: If you need to use an older version of Node.js (>= 6.x), use
node-vault <= v0.10.0. Please be aware thatnode-vault <= v0.10.0contains multiple known vulnerabilities ☠️
TypeScript definitions are included in the package.
Run tests using docker-compose (includes vault and postgres) with:
docker-compose up --force-recreate testconst vault = require('node-vault')({
apiVersion: 'v1', // API version (default: 'v1')
endpoint: 'http://127.0.0.1:8200', // Vault server URL (default: 'http://127.0.0.1:8200')
token: 'MY_TOKEN', // Vault token for authentication
pathPrefix: '', // Optional prefix for all request paths
namespace: 'my-namespace', // Vault Enterprise namespace
noCustomHTTPVerbs: false, // Use GET with ?list=1 instead of LIST HTTP method
requestOptions: {}, // Custom axios request options applied to all requests
});The client reads the following environment variables as defaults:
| Variable | Description |
|---|---|
VAULT_ADDR |
Vault server URL (overridden by endpoint option) |
VAULT_TOKEN |
Vault token (overridden by token option) |
VAULT_NAMESPACE |
Vault Enterprise namespace (overridden by namespace option) |
VAULT_PREFIX |
Request path prefix (overridden by pathPrefix option) |
VAULT_SKIP_VERIFY |
When set, disables SSL certificate verification |
const vault = require('node-vault')({
apiVersion: 'v1',
endpoint: 'http://127.0.0.1:8200',
token: 'MY_TOKEN', // optional; can be set after initialization
});
// init vault server
vault.init({ secret_shares: 1, secret_threshold: 1 })
.then((result) => {
const keys = result.keys;
// set token for all following requests
vault.token = result.root_token;
// unseal vault server
return vault.unseal({ secret_shares: 1, key: keys[0] });
})
.catch(console.error);vault.write('secret/hello', { value: 'world', lease: '1s' })
.then(() => vault.read('secret/hello'))
.then(() => vault.delete('secret/hello'))
.catch(console.error);The update method sends a PATCH request with application/merge-patch+json content type:
vault.update('secret/data/hello', { data: { value: 'new-world' } })
.catch(console.error);vault.list('secret/metadata/')
.then((result) => console.log(result.data.keys))
.catch(console.error);const fs = require('fs');
// Read service account token from default mount path
const jwt = fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/token', { encoding: 'utf8' });
// If the Vault Kubernetes auth endpoint is /auth/example-cluster/login and the role is example-role
vault.kubernetesLogin({
role: 'example-role',
jwt: jwt,
mount_point: 'example-cluster',
}).catch(console.error);const vault = require('node-vault')();
vault.approleLogin({
role_id: 'my-role-id',
secret_id: 'my-secret-id',
})
.then((result) => {
// client token is automatically set on successful login
console.log(result.auth.client_token);
})
.catch(console.error);The client exposes two error types accessible from the module:
VaultError— Base error class for all vault-related errors.ApiResponseError— Thrown on non-200/204 responses. Contains aresponseproperty withstatusCodeandbody.
vault.read('secret/missing')
.catch((err) => {
console.error(err.message); // Error message from Vault
if (err.response) {
console.error(err.response.statusCode); // e.g. 404
console.error(err.response.body); // Response body from Vault
}
});You can register custom API commands using generateFunction:
vault.generateFunction('myCustomEndpoint', {
method: 'GET',
path: '/my-custom/endpoint/{{id}}',
});
// Use the generated function
vault.myCustomEndpoint({ id: 'abc123' })
.then(console.log)
.catch(console.error);Generate docco docs via:
npm run docsPlease have a look at the examples and the generated feature list to see all supported Vault API endpoints.
Instead of installing all the dependencies like vault itself and postgres, you can use docker and docker-compose to link and run multiple docker containers with all of their dependencies.
git clone git@github.com:nodevault/node-vault.git
cd node-vault
docker-compose up vaultNow you can run the examples from another terminal window.
First of all you should initialize and unseal the vault:
node example/init.jsYou should see root_token: followed by a long key in the response.
Please copy that long key and export it as an environment variable:
export VAULT_TOKEN=<insert long key here>Now you are able to run all of the other examples:
node example/policies.jsTo connect to a vault server in a private network through a bastion host, first open a SOCKS proxy connection:
ssh -D <socksPort> bastion.example.comThen configure the client with a SOCKS proxy agent:
const { SocksProxyAgent } = require('socks-proxy-agent');
const agent = new SocksProxyAgent(`socks://127.0.0.1:${socksPort}`);
const vault = require('node-vault')({
apiVersion: 'v1',
requestOptions: {
httpsAgent: agent,
httpAgent: agent,
},
});If you encounter SSL errors after upgrading to Node 18+ (e.g., EPROTO errors related to
unsafe legacy renegotiation disabled), you can pass SSL/TLS options via requestOptions
or rpDefaults when initializing the client:
const vault = require('node-vault')({
apiVersion: 'v1',
endpoint: 'https://vault.example.com:8200',
token: 'MY_TOKEN',
requestOptions: {
agentOptions: {
securityOptions: 'SSL_OP_LEGACY_SERVER_CONNECT',
},
},
});The requestOptions object supports TLS/SSL options (ca, cert, key, passphrase,
agentOptions, strictSSL) as well as timeout, httpsAgent, and httpAgent. TLS options
are mapped to an https.Agent and applied to every request. You can also pass native
axios request options such as custom headers.
You can also pass request options per-call to any method:
vault.read('secret/hello', {
agentOptions: {
securityOptions: 'SSL_OP_LEGACY_SERVER_CONNECT',
},
});See example/pass_request_options.js for more examples.