Hashing
For everything you choose to store as a hash — an API token, an invite code, a one-time secret.
Sign-in passwords do not read this
Those are better-auth's business, and it hashes them itself. This package is for the hashes your own code makes.
import { hash } from '@elvel/hashing'
const digest = await hash().make('secret')
// '$argon2id$v=19$m=19456,t=2,p=1$…'
await hash().check('secret', digest) // true
await hash().check('nope', digest) // falseTwo drivers
// config/hashing.ts
driver: process.env.HASH_DRIVER ?? 'bcrypt',
bcrypt: { cost: 12, limit: 72 },
argon: { memory: 65536, time: 4 }await hash().driver('bcrypt').make('secret') // '$2b$10$…' at cost 10bcrypt is the default and each step of cost doubles the time — 12 is roughly 250ms on current hardware. argon2id is the other, and memory is the parameter that resists a GPU rather than a CPU.
limit: 72 is not arbitrary. bcrypt ignores everything past 72 bytes in most implementations, so a longer value is refused rather than silently truncated — otherwise a 100-character passphrase and its first 72 characters are the same secret and nobody is told. Set it to 0 to allow it, or use argon2id, which has no such ceiling.
Rehashing when the cost changes
hash().needsRehash(digest) // false, until the configured cost moveshash().info(digest)
// { algorithm: 'argon2id', options: { version: 19, memoryCost: 19456, timeCost: 2, threads: 1 } }info() reads the parameters out of the digest itself, which is what makes needsRehash answerable: the stored hash says what it cost, so raising the cost in configuration lets the next successful check re-hash the value at the new one.