Introduction

unsecure is a set of cryptographic utilities built on the Web Crypto API: zero dependencies, one entry point per module, and one typed error.

unsecure is a collection of runtime-agnostic, cryptographically secure utilities. The name is a joke. The defaults are not.

Everything here is built on the Web Crypto API and the platform's own CSPRNG. There are no runtime dependencies, no Node built-ins, and no WebAssembly, so the same code runs in Node, Bun, Deno, Cloudflare Workers and browsers.

#What is in the box

FamilyFunctions
Hashing and MAChash, hmac, hmacVerify, importHmacKey
Key derivationhkdf, importHkdfKey
Password hashingargon2, argon2Hash, argon2Verify, argon2NeedsRehash
One-time passwordshotp, totp, their verifies, generateOTPSecret, otpauthURI
UUIDuuidv4, uuidv7, createUUIDv7Generator, uuidv7Timestamp, the type guards
SecretssecureGenerate, secureCompare, entropy
SanitizesanitizeObject, sanitizeObjectCopy, safeJsonParse
RandomsecureRandomNumber, secureRandomBytes, secureShuffle, randomJitter
CodecsHex, Base64, Base32 and their flat stringify / parse functions
ErrorsUnsecureError and its code set

#Two rules that run through everything

Verification never throws on untrusted input. secureCompare, hmacVerify, hotpVerify, totpVerify and argon2Verify return false for a missing header, a malformed signature or a wrong-typed value from a JSON body. They throw only for something you control: an empty secret, an unsupported algorithm, an out-of-range window. So a try / catch around a verify is about your own configuration, never about the request.

One error class, one code set. Every failure is an UnsecureError with a code you can branch on. A native TypeError escaping the library is a bug.

#What it looks like

import { argon2Hash, argon2Verify } from "unsecure/argon2";
import { hmacVerify } from "unsecure/hmac";
import { uuidv7 } from "unsecure/uuid";

const stored = await argon2Hash("correct horse battery staple");
// "$argon2id$v=19$m=19456,t=2,p=1$…$…"

await argon2Verify(stored, "correct horse battery staple"); // true
await argon2Verify(stored, "hunter2"); // false

await hmacVerify(secret, body, request.headers.get("x-signature")); // boolean

uuidv7(); // "01a076ba-1e53-7411-8518-84905f353e3d"

#What is not in the box

JWT, JWS, JWE and JWK are intentionally out of scope, and will stay that way. unjwt covers the whole JOSE toolset with the same runtime-agnostic, Web Crypto approach; the two libraries are meant to sit side by side.

#Where to go next