Vault Plugin
Secure encrypted vault for managing secrets and credentials with AES-256-GCM encryption, session management, and dual interface (CLI tool and TokenRing service).
Overview
The @tokenring-ai/vault package provides a secure, encrypted vault for managing secrets and credentials. It works both as a standalone CLI tool and as a TokenRing service for programmatic access. The vault uses AES-256-GCM encryption with PBKDF2 key derivation for industry-standard security, and includes session management with automatic locking.
Key Features
- AES-256-GCM Encryption: Industry-standard encryption for secrets at rest
- Dual Interface: CLI tool and TokenRing service
- Environment Variable Injection: Run commands with vault secrets as env vars
- Secure Password Input: Hidden password entry in terminal with masking
- Restrictive Permissions: Vault files created with 0o600 (owner-only access)
- Session Management: Automatic locking and password caching during session
- Interactive CLI: Full featured command-line interface with password masking
- TokenRing Integration: Seamless integration with TokenRing application framework
- Service Architecture: Plugin-based service registration and configuration
- Chat Commands: Integrated chat commands for agent interaction (/vault unlock, lock, list, store, get)
- Automatic Relocking: Vault automatically locks after 5 minutes of inactivity
- Zod Configuration: Type-safe configuration with schema validation
Chat Commands
The vault package provides integrated chat commands for managing credentials within the agent interface:
/vault unlock
Unlock the vault with password
/vault lock
Lock the vault
/vault list
List all credential keys in the vault
/vault store <key>
Store a credential in the vault
- Prompts for the credential value securely
/vault get <key>
Retrieve and display a credential from the vault
Example usage:
/vault unlock
/vault list
/vault store api_key
/vault get api_key
/vault lock
CLI Usage
Initialize Vault
vault init
vault init -f ~/.secrets.vault
Creates a new encrypted vault file. You'll be prompted to set a password.
Store Secrets
vault set API_KEY sk-1234567890
vault set DB_PASSWORD mySecretPassword
vault set -f ~/.secrets.vault AWS_KEY abc123
Retrieve Secrets
vault get API_KEY
vault get DB_PASSWORD
List Keys
vault list
Shows all secret keys (not values) stored in the vault.
Remove Secrets
vault remove API_KEY
vault remove OLD_TOKEN
Change Password
vault change-password
Re-encrypts the vault with a new password.
Run Commands with Secrets
vault run -- node app.js
vault run -- bun start
vault run -- bash -c 'echo $API_KEY'
Executes a command with all vault secrets injected as environment variables. Only string values are injected.
CLI Commands
vault init
Initialize a new encrypted vault file.
Options:
-f, --file <path>: Specify vault file path (default:.vault)
vault get <key>
Retrieve a secret value by key.
vault set <key> <value>
Store a secret value.
vault list
List all secret keys (not values) stored in the vault.
vault remove <key>
Remove a secret by key.
vault change-password
Change the vault encryption password.
vault run <command> [args...]
Run a command with vault secrets injected as environment variables.
TokenRing Service Usage
Configuration
import { VaultService } from '@tokenring-ai/vault';
import { vaultConfigSchema } from '@tokenring-ai/vault';
const vault = new VaultService({
vaultFile: '.vault',
relockTime: 300000 // 5 minutes in milliseconds
});
Service Methods
unlockVault(agent: Agent): Promise<Record<string, string>>
Prompts for password and unlocks the vault. Returns the vault data.
const data = await vault.unlockVault(agent);
Parameters:
agent: The current agent instance for service access and human interaction
Returns:
Promise<Record<string, string>>: The decrypted vault data as key-value pairs
lock(): Promise<void>
Locks the vault and clears cached password and data.
await vault.lock();
getItem(key: string, agent: Agent): Promise<string | undefined>
Retrieves a value by key. Unlocks vault if needed. Returns string or undefined.
const apiKey = await vault.getItem('API_KEY', agent);
Parameters:
key: The key to retrieveagent: The current agent instance
Returns:
Promise<string | undefined>: The value or undefined if key doesn't exist
setItem(key: string, value: string, agent: Agent): Promise<void>
Stores a string value by key. Unlocks vault if needed.
await vault.setItem('API_KEY', 'sk-1234567890', agent);
Parameters:
key: The key to storevalue: The string value to storeagent: The current agent instance
save(vaultData: Record<string, string>, agent: Agent): Promise<void>
Saves the entire vault data.
await vault.save({ API_KEY: 'new-key', DB_PASSWORD: 'new-pass' }, agent);
Parameters:
vaultData: The complete vault data to saveagent: The current agent instance
Service Features
- Password Caching: Password cached during session, cleared on lock
- Automatic Locking: Vault locks after configured timeout (default: 5 minutes)
- Session Management: Relock timer resets on each access
- Plugin Integration: Auto-registers with TokenRing application framework
- Agent Integration: Uses Agent's human interaction for password prompts
- Chat Command Integration: Provides subcommands for agent interaction
- Error Handling: Comprehensive error handling with descriptive messages
- Configuration Validation: Zod schema validation for configuration
- Human Interface: Integrates with Agent's
askForTextrequest type with masking
Plugin Integration
The vault package integrates with TokenRing applications through a plugin system:
import { TokenRingPlugin } from "@tokenring-ai/app";
import { VaultService } from "@tokenring-ai/vault";
import { VaultConfigSchema } from "@tokenring-ai/vault/schema";
import chatCommands from "@tokenring-ai/vault/chatCommands";
import packageJSON from "@tokenring-ai/vault/package.json";
export default {
name: packageJSON.name,
version: packageJSON.version,
description: packageJSON.description,
install(app, config) {
if (config.vault) {
app.addServices(new VaultService(config.vault));
app.waitForService(AgentCommandService, commandService => {
commandService.addAgentCommands(chatCommands)
});
}
},
config: z.object({ vault: VaultConfigSchema.optional() })
} satisfies TokenRingPlugin;
Configuration Schema
import { z } from 'zod';
export const VaultConfigSchema = z.object({
vaultFile: z.string().min(1),
relockTime: z.number().positive().default(300 * 1000),
});
Configuration Options:
vaultFile: Path to vault file (default:.vault)relockTime: Auto-lock timeout in milliseconds (default: 300000)
Programmatic Vault Access
For direct vault file manipulation without the service layer:
import { readVault, writeVault, initVault, deriveKey } from '@tokenring-ai/vault/vault';
import fs from 'fs-extra';
// Initialize new vault
await initVault('.vault', 'myPassword');
// Read vault (returns Record<string, string>)
const data = await readVault('.vault', 'myPassword');
// Write vault (accepts Record<string, string>)
await writeVault('.vault', 'myPassword', { API_KEY: 'value' });
// Derive encryption key from password and salt
const salt = crypto.randomBytes(16);
const key = deriveKey('myPassword', salt);
Data Types
The vault stores string key-value pairs:
- Keys: strings
- Values: strings
Security
Encryption
- Algorithm: AES-256-GCM (Galois/Counter Mode)
- Key Derivation: PBKDF2 with 100,000 iterations using SHA-256
- Salt: 16 random bytes per encryption
- IV: 12 random bytes per encryption
- Authentication: GCM provides authenticated encryption
- File Permissions: Vault files created with
0o600(owner read/write only)
Best Practices
- Use strong, unique passwords for vault encryption
- Store vault files in secure locations
- Don't commit vault files to version control
- Use
.gitignoreto exclude vault files - Rotate secrets regularly
- Use different vaults for different environments
- Use the auto-lock feature to prevent unauthorized access
- Use chat commands for secure credential management in agents
Usage Example
CLI Workflow
# Initialize vault
vault init -f .production.vault
# Store production secrets
vault -f .production.vault set DATABASE_URL postgres://...
vault -f .production.vault set API_KEY sk-prod-...
vault -f .production.vault set JWT_SECRET random-secret
# List stored keys
vault -f .production.vault list
# Run application with secrets
vault -f .production.vault run -- node server.js
TokenRing Integration
import { Agent } from '@tokenring-ai/agent';
import { VaultService } from '@tokenring-ai/vault';
const agent = new Agent({
services: [
new VaultService({
vaultFile: '.vault',
relockTime: 300000
})
]
});
// Access vault through agent
const vault = agent.getService('VaultService');
const apiKey = await vault.getItem('API_KEY', agent);
// Or use chat commands
// /vault unlock
// /vault get API_KEY
Environment Variable Pattern
# Store all environment variables
vault set NODE_ENV production
vault set PORT 3000
vault set DATABASE_URL postgres://localhost/mydb
vault set REDIS_URL redis://localhost:6379
# Run with all secrets injected
vault run -- bun start
Error Handling
The vault package provides comprehensive error handling:
- Invalid Password:
Failed to decrypt vault. Invalid password or corrupted vault file. - File Not Found:
Vault file does not exist - Empty Password:
Password was empty, vault unlock cancelled - Save Without Unlock:
Vault must be unlocked before saving - File Permissions: Proper error handling for file system issues
try {
const data = await readVault('.vault', password);
} catch (error) {
// Handle invalid password or corrupted vault
console.error('Failed to decrypt vault');
}
Package Structure
pkg/vault/
├── cli.ts # CLI implementation with Commander
├── index.ts # Package exports
├── plugin.ts # TokenRing plugin integration
├── VaultService.ts # TokenRing service implementation
├── vault.ts # Core encryption and file operations
├── schema.ts # Zod configuration schema
├── chatCommands.ts # Chat commands for agent integration
├── commands/ # Chat command implementations
│ ├── vault.ts # Main command router
│ ├── unlock.ts # Unlock command
│ ├── lock.ts # Lock command
│ ├── list.ts # List command
│ ├── store.ts # Store command
│ └── get.ts # Get command
├── vitest.config.ts # Vitest configuration
├── LICENSE # MIT license
├── package.json # Package configuration
└── README.md # Package documentation
Testing
The package includes Vitest configuration for testing:
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
include: ["**/*.test.ts"],
environment: "node",
globals: true,
isolate: true,
},
});
License
MIT (see LICENSE file)