SecureKit
SecureKit is a zero-runtime-dependency Node.js package for authenticated encryption and the application concerns that usually accumulate around it. The simplest path stays small: install it, provide a key, call encrypt() and decrypt().
Version
0.9.0
Runtime
Node.js >=20
License
MIT
Runtime deps
0
Install
Install the package from npm. SecureKit targets modern Node.js and uses the platform crypto implementation rather than pulling in a cryptography dependency tree.
terminal
npm
npm i @bybence/securekit
Generate a canonical 256-bit Base64 key with the included CLI, then keep the key in your server-side environment rather than in client code or source control.
terminal
key setup
npx securekit generate-key # .env.local SECUREKIT_KEY=<generated-base64-key>
Quick start
For a basic encrypted value, the public surface is intentionally short. The returned token is versioned so the package can identify its own format when reading it later.
secure-data.mjs
ESM
import { encrypt, decrypt } from "@bybence/securekit";
const email = "hello@example.com";
const token = encrypt(email);
const value = decrypt(token);
console.log(value);
// "hello@example.com"Purpose binding
Purpose binding separates classes of encrypted data. A token created for one purpose should be decrypted with that same purpose, which helps prevent values from being moved between unrelated application fields by mistake.
purpose.mjs
recommended for distinct data classes
const token = encrypt(email, {
purpose: "user.email",
});
const emailAgain = decrypt(token, {
purpose: "user.email",
});Blind indexes
Normal randomized encryption is intentionally unsuitable for direct equality queries. A blind index gives you a separate deterministic lookup value without making the ciphertext itself deterministic.
lookup.mjs
exact-match lookup
import { blindIndex } from "@bybence/securekit";
const emailIndex = blindIndex(email, {
normalize: "email",
});
// Store emailIndex next to the encrypted value
// and query the index for exact matches.Key rotation
Tokens carry enough version and key metadata for the application to detect values that should be moved to the current key. Rotation can happen gradually when data is read instead of requiring one all-at-once migration.
rotation.mjs
lazy rotation
import { needsReencrypt, rotate } from "@bybence/securekit";
if (needsReencrypt(token)) {
const rotatedToken = rotate(token);
// persist rotatedToken
}Sealed values
Sealed values are useful when application data should carry an authenticated expiration time. Expiration becomes part of the protected value instead of a separate convention the caller can accidentally skip.
sealed.mjs
time-bound data
import { seal } from "@bybence/securekit";
const token = seal(
{ action: "verify-email", userId: 123 },
{ expiresIn: "15m" }
);Passwords
Passwords are not encrypted. SecureKit exposes password hashing separately so application code does not accidentally treat passwords like reversible secrets. The package uses scrypt for this path.
password.mjs
one-way hashing
import { hashPassword } from "@bybence/securekit";
const passwordHash = await hashPassword(password);Do not use encrypt() as a replacement for password hashing. Password storage has a different threat model and should stay one-way.
CLI
The CLI handles setup and inspection tasks that are useful during development and deployment. The same package provides the runtime API and the diagnostics, so the checks stay aligned with the installed version.
terminal
available commands
npx securekit init npx securekit generate-key npx securekit doctor npx securekit inspect <token> npx securekit guide
Security notes
Authenticated encryption
The encryption path uses AES-256-GCM and a fresh 96-bit IV per encryption.
Key derivation
Purpose-separated key material is derived with HKDF-SHA-256.
Versioned format
SecureKit emits a versioned sk4 token so parsing and migrations do not depend on an undocumented byte layout.
Scope
SecureKit is an application library, not an independent security audit or a replacement for architecture-level key management decisions.