Secrets

Lucent Secrets stores JSON secrets encrypted in the database. It is designed for server-side credentials such as service account private keys, API keys, and integration tokens.

Secrets are encrypted with AES-256-GCM. The encrypted record is stored in lucent_secrets; the master key must come from outside the database, usually an environment variable.

Configuration

export default defineLucentConfig({
  secrets: {
    enabled: true,
    masterKey: Bun.env.LUCENT_SECRETS_KEY,
    keyVersion: "v1",
  },
});

Generate a master key:

import { LucentSecrets } from "@codesordinatestudio/lucent";

console.log(LucentSecrets.generateMasterKey());

Store the generated value in LUCENT_SECRETS_KEY. Keep a backup outside the app database. If the master key is lost, existing encrypted secrets cannot be recovered.

Standalone Usage

import { LucentSecrets } from "@codesordinatestudio/lucent";

const secrets = LucentSecrets.create({
  adapter,
  masterKey: Bun.env.LUCENT_SECRETS_KEY!,
});

const key = LucentSecrets.key("tenant", tenantId, "googleDrive", "serviceAccount");

await secrets.set(key, {
  clientEmail,
  privateKey,
});

const record = await secrets.require<{ clientEmail: string; privateKey: string }>(key);

Key Convention

Use scoped keys:

scope:ownerId:provider:name

Examples:

tenant:tenant_123:googleDrive:serviceAccount
user:user_456:stripe:apiKey
app:default:resend:apiKey

LucentSecrets.key(scope, ownerId, provider, name) builds this format and rejects empty parts.

Local API Usage

When secrets.enabled and secrets.masterKey are configured, the Local API includes lucent.secrets:

const lucent = await getLucent(config);

await lucent.secrets?.set("app:default:resend:apiKey", {
  apiKey: "re_...",
});

Rotation

Secrets store a keyVersion beside the encrypted payload. To rotate keys, decrypt with the old key, re-encrypt with the new key, then retire the old key:

const oldSecrets = LucentSecrets.create({ adapter, masterKey: oldKey, keyVersion: "v1" });

await oldSecrets.rotate("app:default:resend:apiKey", {
  adapter,
  masterKey: newKey,
  keyVersion: "v2",
});

Do not change LUCENT_SECRETS_KEY without rotating existing records first.