← All @molecule/* packages · App templates
@molecule/api-encryption-aesProvider bond · encryption · API (Node) · v1.0.1 · Apache-2.0
AES-256-GCM encryption provider for molecule.dev — authenticated encryption, SHA-256 hashing, and key rotation
npm install @molecule/api-encryption-aesnpm · Source on GitHub · Implements @molecule/api-encryption
@molecule/api-encryption-aes is a provider bond on the API (Node) side: it implements the encryption core interface (@molecule/api-encryption) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
import { setProvider } from '@molecule/api-encryption'
import { provider } from '@molecule/api-encryption-aes'
// Wire the provider at startup (reads ENCRYPTION_KEY from env)
setProvider(provider)
// Or create with explicit config
import { createProvider } from '@molecule/api-encryption-aes'
const customProvider = createProvider({ key: 'your-64-char-hex-key' })
setProvider(customProvider)Works with: @molecule/api-encryption, @molecule/api-secrets
Secrets: ENCRYPTION_KEY
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
AES-256-GCM encryption provider for molecule.dev.
Uses Node.js built-in crypto for AES-256-GCM authenticated encryption,
SHA-256 hashing, and timing-safe verification. Supports key rotation with
versioned ciphertext format.
import { setProvider } from '@molecule/api-encryption'
import { provider } from '@molecule/api-encryption-aes'
// Wire the provider at startup (reads ENCRYPTION_KEY from env)
setProvider(provider)
// Or create with explicit config
import { createProvider } from '@molecule/api-encryption-aes'
const customProvider = createProvider({ key: 'your-64-char-hex-key' })
setProvider(customProvider)
provider
npm install @molecule/api-encryption-aes @molecule/api-encryption @molecule/api-secrets
AesConfigConfiguration options for the AES-256-GCM encryption provider.
interface AesConfig {
/** The current 256-bit encryption key, hex-encoded (64 hex characters). */
key: string
/**
* Version of the current `key`. Ciphertext produced by `encrypt()` is tagged
* with this version; `decrypt()` selects the key to use from the `v{n}` tag,
* so it must be stable for a given key. `rotateKey()` advances it.
*
* @default 1
*/
keyVersion?: number
/**
* Prior keys to seed the keyring with, so ciphertext encrypted before a
* rotation still decrypts after this provider is (re)constructed — e.g. on a
* process restart, when the in-memory rotation state would otherwise be lost.
* Each entry maps a historical `v{n}` version to its key. The current `key`
* (at {@link AesConfig.keyVersion}) always wins over any prior entry sharing
* its version.
*
* @default []
*/
priorKeys?: PriorKey[]
}
AesEncryptionProviderAES-256-GCM encryption provider.
Fully satisfies the core EncryptionProvider contract, so it bonds anywhere
an EncryptionProvider is expected. It additionally exposes
{@link AesEncryptionProvider.pruneKeyVersions} to explicitly retire old keys
once their ciphertext has been re-encrypted — rotation alone never drops a
key, so it can never orphan data.
interface AesEncryptionProvider extends EncryptionProvider {
/**
* Retires key versions from the in-memory keyring. Call this only AFTER every
* ciphertext encrypted under those versions has been re-encrypted under the
* current key — a pruned version can no longer decrypt its ciphertext.
*
* The current key version is ALWAYS retained (it cannot be pruned). By
* default every non-current version is removed; pass `keep` to retain
* specific older versions during a staged migration.
*
* @param keep - Old versions to retain in addition to the current one.
* @returns The versions that were removed.
*/
pruneKeyVersions(keep?: number[]): number[]
}
PriorKeyA historical (pre-rotation) key, retained so ciphertext encrypted under it remains decryptable.
Ciphertext is tagged with the v{version} of the key that produced it; the
provider selects the matching key from its keyring at decrypt time. Seed the
keyring with the app's prior keys (from a secret store) so rotations survive
a process restart — see {@link AesConfig.priorKeys}.
interface PriorKey {
/** The key version tag this key decrypts (matches the `v{n}` ciphertext prefix). */
version: number
/** The 256-bit key, hex-encoded (64 hex characters). */
key: string
}
createProvider(config)Creates an AES-256-GCM encryption provider.
Rotation is transition-safe: keys are held in a version-keyed keyring.
encrypt() tags each ciphertext with the current key version, decrypt()
selects the key named by that tag, and rotateKey() ADDS the new key while
keeping prior keys — so ciphertext from before a rotation still decrypts.
Retire old keys explicitly (once their data is re-encrypted) via
pruneKeyVersions().
function createProvider(config: AesConfig): AesEncryptionProvider
config — Provider configuration including the hex-encoded 256-bit key.Returns: An AesEncryptionProvider using AES-256-GCM.
encryptionAesSecretDefinitionsSecret definitions required by the AES encryption bond.
const encryptionAesSecretDefinitions: SecretDefinition[]
providerDefault AES-256-GCM encryption provider instance.
Lazily initializes on first property access using the ENCRYPTION_KEY
environment variable (hex-encoded 256-bit key). This singleton starts a
fresh keyring at version 1 on each process, so a rotation performed in a
prior process is NOT restored here — for rotation that survives restarts,
construct with createProvider({ key, priorKeys }) seeding the historical
keys from your secret store.
const provider: AesEncryptionProvider
Implements @molecule/api-encryption interface.
Setup function to register this provider with the core interface:
import { setProvider } from '@molecule/api-encryption'
import { provider } from '@molecule/api-encryption-aes'
export function setupEncryptionAes(): void {
setProvider(provider)
}
Peer dependencies:
@molecule/api-encryption ^1.0.1@molecule/api-secrets ^1.0.1ENCRYPTION_KEY (required) — AES-256 encryption key
@molecule/api-encryption
@molecule/api-secrets
rotateKey() is transition-safe — it never orphans data. Keys live in
a version-keyed keyring: encrypt() tags each ciphertext with the current
v{n}, decrypt() reads that tag and selects the matching key, and
rotateKey(oldKey, newKey) ADDS newKey at the next version while RETAINING
the prior key(s). So ciphertext written before a rotation still decrypts
afterward (the core contract's "previously encrypted data can still be
decrypted during a transition period"). Once you have re-encrypted the old
ciphertext under the new key, retire the old keys explicitly with
pruneKeyVersions() — rotation alone deliberately keeps them.
A ciphertext whose v{n} version is not in the keyring (unknown/pruned key)
fails cleanly with a descriptive error — never a silent wrong decrypt.
Rotation state is per-process and in-memory: the lazy provider singleton
starts a fresh keyring at version 1 from ENCRYPTION_KEY on each process,
so a rotation done in a prior process is not restored. For rotation that
survives restarts, build with createProvider({ key, priorKeys }), seeding
the historical { version, key } entries from your secret store.
hash()/verify() are plain unsalted SHA-256 — integrity checks only.
NEVER use them for passwords; use @molecule/api-password with a bond
like @molecule/api-password-bcrypt.
encrypt(plaintext, context): the optional context is GCM AAD — the
SAME context string must be supplied to decrypt() or authentication
fails.