Convex component: secret-manager
  • TypeScript 100%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
phantasy 1eade4e0ab Merge envelope randomness fallback
Use the Convex seeded PRNG for all AES-GCM key and IV randomness in mutations.
2026-09-27 01:20:01 +00:00
example docs: add example Convex app and GitHub homepage for the directory 2026-09-11 18:46:07 -04:00
src fix(crypto): cover envelope randomness in mutations 2026-09-26 21:12:09 -04:00
.gitignore feat: initial convex-secret-manager component (vault + issued keys) 2026-07-01 01:21:21 -04:00
bun.lock chore: publish-ready Convex component package metadata 2026-07-05 17:42:29 -04:00
LICENSE feat: initial convex-secret-manager component (vault + issued keys) 2026-07-01 01:21:21 -04:00
package-lock.json feat: v0.2.0 parity with gaganref (envelope crypto, sweeps, refresh, audit) 2026-07-01 01:37:42 -04:00
package.json docs: add example Convex app and GitHub homepage for the directory 2026-09-11 18:46:07 -04:00
README.md docs: explain app-side encryption mode 2026-09-26 21:16:36 -04:00
tsconfig.build.json feat: initial convex-secret-manager component (vault + issued keys) 2026-07-01 01:21:21 -04:00
tsconfig.json feat: initial convex-secret-manager component (vault + issued keys) 2026-07-01 01:21:21 -04:00
vitest.config.ts feat: v0.2.0 parity with gaganref (envelope crypto, sweeps, refresh, audit) 2026-07-01 01:37:42 -04:00

convex-secret-manager

Convex component for encrypted secret vaults and issued API key lifecycle.

Combines the roles of gaganref/convex-secret-store and gaganref/convex-api-keys into one package with per-ownerId tenancy. Any Convex app can use it (SaaS orgs, agents, multi-tenant backends).

Two modules

Module Use
Vault Store user-supplied credentials (OpenAI, Venice, webhooks) encrypted at rest
Issued keys Issue sm_ machine tokens with hash-only storage, refresh, revoke, and audit

vs gaganref

gaganref (2 packages) convex-secret-manager
Path model namespace + name ownerId + namespace + name
Use case Generic apps Multi-tenant backends that issue keys too
Install Two components One component
Vault crypto Envelope + KEK rotation Envelope (defineKeys) + legacy single-key
Issued validate Query (side-effect free) Query
Sweeps Hourly crons Hourly crons (built-in)

Use gaganref when you need only one concern. Use this package when one owner should hold both third-party credentials and issued machine tokens.

Install

npm install convex-secret-manager
// convex/convex.config.ts
import { defineApp } from "convex/server";
import { v } from "convex/values";
import { defineKeys } from "convex-secret-manager";
import secretManager from "convex-secret-manager/convex.config.js";

const app = defineApp({
  env: {
    MY_APP_KEK_V1: v.string(),
  },
});

app.use(secretManager, {
  env: {
    SECRET_MANAGER_KEYS: defineKeys({
      1: process.env.MY_APP_KEK_V1!,
    }),
  },
});

export default app;
// convex/secrets.ts
import { SecretManager } from "convex-secret-manager";
import { components } from "./_generated/api.js";

export const secretManager = new SecretManager(components.secretManager);

Set on the Convex deployment:

SECRET_MANAGER_KEYS=1:<kek-material>
# or legacy single key:
SECRET_MANAGER_ENCRYPTION_KEY=...

Self-hosted Convex app-side encryption

When component functions cannot read the host deployment's environment, perform encryption and decryption inside trusted host functions:

export const secretManager = new SecretManager(components.secretManager, {
  useComponentEncryption: false,
});

The host deployment must provide SECRET_MANAGER_ENCRYPTION_KEY or SECRET_MANAGER_KEYS. This mode stores only ciphertext in the component. Its ciphertext lookup is a public component query; expose it only through host functions that enforce application authorization, never directly to untrusted clients.

Vault paths

ownerId   = orgId | userId | deployment
namespace = providers | integrations | webhooks
name      = openai.apiKey

Issued keys API (parity highlights)

  • issued.create / validate (query) / touch / revoke / revokeAll
  • issued.refresh — rotate with grace period
  • issued.update / getKey / list (paginated + effectiveStatus)
  • Hourly sweep crons for expired and idle keys
  • cleanupKeys / cleanupEvents internal jobs

Vault API (parity highlights)

  • vault.putPlaintext — component-side envelope encryption with AAD
  • vault.getResult — { ok, value } | { ok: false, reason }
  • vault.update — metadata/TTL without re-encrypt
  • vault.list — paginated with effectiveState
  • auditEvents.listEvents — paginated audit trail
  • vaultRotate.rotate / isRotationComplete — KEK rotation drain
  • vaultCleanup.cleanupSecrets — expired secret cleanup

Example

See example/ for a minimal Convex + Vite dashboard.

License

MIT