API Keys & Scoping

Create scoped API keys for programmatic access — understand scope dimensions, vault restrictions, and zero-downtime key rotation.

beginner10 min read

What You'll Build

API keys are the preferred credential for server-to-server integrations, CI/CD pipelines, and automation scripts. Unlike session-based login tokens, API keys are long-lived and carry explicit permission scopes — you decide exactly what each key is allowed to do.

By the end of this guide you will have:

  • A scoped API key suitable for programmatic vault access
  • A clear understanding of the scope system and how vault restrictions work
  • A zero-downtime rotation strategy for updating keys in production

API keys use the lsv_k_ prefix and are looked up by their 8-character prefix for fast server-side verification. The full key is only returned once at creation time.

Prerequisites

  • A Lifestream Vault account (any tier — API keys are available on all tiers)
  • Node.js 18+ if using the SDK or CLI

Create an API Key

API keys can be created via the UI (Settings → API Keys → New Key), the SDK, or the CLI. When creating a key you specify:

  • Name — a human-readable label to identify the key's purpose (e.g. "CI/CD Deploy Key")
  • Scopes — the set of permissions granted to the key (see the Scoping section below)
  • Vault ID (optional) — restrict the key to a single vault; omit to allow access to all user vaults
typescript
import { LifestreamVaultClient } from '@lifestreamdynamics/vault-sdk';

const { client } = await LifestreamVaultClient.login(
  'https://vault.lifestreamdynamics.com',
  'you@example.com',
  'your-password',
);

const key = await client.apiKeys.create({
  name: 'CI/CD Deploy Key',
  scopes: ['read', 'write'],
  vaultId: 'optional-vault-id', // omit to allow all vaults
});

// The full key value (lsv_k_...) is shown only once — store it immediately
console.log('API Key:', key.key);
console.log('Key ID:', key.id); // use this to delete or manage the key later

The full API key is only shown once at creation time. Copy it immediately and store it in a secrets manager (AWS Secrets Manager, HashiCorp Vault, GitHub Actions secrets, etc.). The server stores only the hashed key — it cannot be retrieved again. If you lose it, delete the key and create a new one.

Understanding Scopes and Vault Restrictions

Scopes control which operations an API key is permitted to perform. When your key is used in a request, the requireScope(scope) middleware checks that the key includes the required scope. JWT-authenticated users (browser sessions) pass scope checks unrestricted.

Available scopes:

ScopeAllows
readRead documents, list vaults, execute searches, read calendar data
writeCreate, update, and delete documents; manage webhooks, calendar events, and vault settings

Vault restrictions limit which vault(s) a key can access. A vault-restricted key cannot access other vaults, even if the user has permission — the server enforces this via the requireVaultAccess middleware.

  • Unrestricted key — can access all vaults the user owns or has access to
  • Vault-scoped key — created with a specific vaultId; all requests are confined to that vault, regardless of which vault ID is passed in the request

Vault scoping is enforced server-side; you cannot bypass it by passing a different vault ID in the request body.

Rotating Keys

Zero-downtime key rotation is a three-phase process:

  1. Create a new key with the same scopes as the old one
  2. Update your application to use the new key (deploy the new configuration)
  3. Verify the new key works, then delete the old key

There is no overlap period required — the old key remains valid until you explicitly delete it, giving you time to roll out the new key across all services.

typescript
// Step 1 — create a replacement key with the same scopes
const newKey = await client.apiKeys.create({
  name: 'CI/CD Deploy Key v2',
  scopes: ['read', 'write'],
  vaultId: 'your-vault-id',
});

console.log('New key (store immediately):', newKey.key);

// --- Deploy newKey.key to your application, verify it works ---

// Step 2 — delete the old key once the new key is confirmed working
const OLD_KEY_ID = 'old-key-uuid'; // from your records or list API
await client.apiKeys.delete(OLD_KEY_ID);

console.log('Old key deleted. Rotation complete.');

Best Practices

  • Least privilege — only grant scopes your application actually needs. A reporting script needs read, not write.

  • Vault-scope when possible — restrict keys to a single vault if the application only needs access to one. A compromised vault-scoped key cannot affect other vaults.

  • Audit regularly — list keys with lsvault keys list or in Settings → API Keys and delete any that are unused, unnamed, or from decommissioned systems.

  • Never expose client-side — API keys should only exist in server-side code, CI/CD pipeline secrets, and CLI configuration. Never embed a lsv_k_ key in frontend JavaScript — it will be visible to anyone who reads your page source.

  • Use environment variables — store keys in environment variables (e.g. LSVAULT_API_KEY) and load them at runtime. Never commit keys to version control, even in private repositories.

  • Name descriptively — include the purpose and environment in the key name so you know immediately what each key is for: "Production Analytics Read-Only", "Staging CI Deploy Bot", "Local Dev Webhook Receiver".

What's Next

  • Build a Custom Integration — use your API key to build a complete programmatic integration with the Lifestream Vault SDK, including batch operations and HMAC request signing
  • Set Up Your First Webhook — configure outbound notifications triggered by vault events and call back into the API from your webhook handler using an API key
  • Secure Your Account with MFA — add multi-factor authentication to your account for defence-in-depth alongside API key security