Skip to content

createHash

API reference for createHash — bcrypt password hashing and custom hash support.

Updated View as Markdown

Signature

function createHash(config?: HashConfig): HashInstance

Creates a password hashing instance powered by bcrypt. Uses bcryptjs (pure JavaScript, edge runtime compatible) under the hood.

import { createHash } from 'ideal-auth';

const hash = createHash();

HashConfig

interface HashConfig {
  rounds?: number;
}
Field Type Required Default
rounds number No 12

The rounds parameter controls the bcrypt cost factor. Higher values are more secure but slower. Each increment roughly doubles the computation time.

const hash = createHash({ rounds: 14 });

HashInstance

make

make(password: string): Promise<string>

Hashes a password using bcrypt and returns the hash string. Throws if the password is empty.

Each call produces a different hash because bcrypt generates a random salt every time.

const hash = createHash();

const hashed = await hash.make('my-secure-password');
// "$2a$12$..."

// Each call produces a different result
const hashed2 = await hash.make('my-secure-password');
// "$2a$12$..." (different from hashed)
try {
  await hash.make('');
} catch (error) {
  // Error: password must not be empty
}

verify

verify(password: string, hash: string): Promise<boolean>

Compares a plain-text password against a bcrypt hash. Returns true if they match, false otherwise.

const hash = createHash();

const hashed = await hash.make('my-secure-password');

await hash.verify('my-secure-password', hashed); // true
await hash.verify('wrong-password', hashed);     // false

Prehash behavior

Passwords longer than 72 UTF-8 bytes are automatically SHA-256 prehashed before being passed to bcrypt. This is because bcrypt truncates input at 72 bytes — without prehashing, two passwords that share the same first 72 bytes would produce identical hashes.

The prehash is transparent. You do not need to do anything special; make() and verify() handle it automatically.

const hash = createHash();

// This 100-character password exceeds 72 UTF-8 bytes.
// It is automatically SHA-256 prehashed before bcrypt processes it.
const longPassword = 'a'.repeat(100);
const hashed = await hash.make(longPassword);

// Verification works identically — prehash is applied automatically
await hash.verify(longPassword, hashed); // true

Usage with createAuth

Pass the HashInstance to createAuth to enable the Laravel-style attempt() flow:

import { createAuth, createHash } from 'ideal-auth';

const hash = createHash();

const auth = createAuth({
  secret: process.env.AUTH_SECRET!,
  cookie: cookieBridge,
  resolveUser: async (id) => db.user.findUnique({ where: { id } }),
  resolveUserByCredentials: async (creds) =>
    db.user.findUnique({ where: { email: creds.email } }),
  hash,
});

Registration example

Use make() to hash passwords before storing them in your database:

import { createHash } from 'ideal-auth';

const hash = createHash();

async function registerUser(email: string, password: string) {
  const hashedPassword = await hash.make(password);

  const user = await db.user.create({
    data: {
      email,
      password: hashedPassword,
    },
  });

  return user;
}

Custom HashInstance

You don’t have to use createHash(). Any object that implements HashInstance works with createAuth. This lets you use your runtime’s native hashing or a different algorithm without pulling in bcryptjs.

import { prehash } from 'ideal-auth';
import type { HashInstance } from 'ideal-auth';

const hash: HashInstance = {
  make: (password) => Bun.password.hash(prehash(password), {
    algorithm: 'bcrypt',
    cost: 12,
  }),
  verify: (password, hash) => Bun.password.verify(prehash(password), hash),
};

Bun’s native bcrypt is significantly faster than bcryptjs (native implementation vs. pure JavaScript). prehash applies SHA-256 for passwords exceeding bcrypt’s 72-byte input limit, preventing silent truncation — the same protection that createHash() applies automatically.

import type { HashInstance } from 'ideal-auth';

const hash: HashInstance = {
  make: (password) => Bun.password.hash(password, {
    algorithm: 'argon2id',
    memoryCost: 65536, // 64 MB
    timeCost: 2,
  }),
  verify: (password, hash) => Bun.password.verify(password, hash),
};

Argon2id is the current OWASP recommendation for password hashing. It is resistant to both GPU and side-channel attacks.

import argon2 from 'argon2';
import type { HashInstance } from 'ideal-auth';

const hash: HashInstance = {
  make: (password) => argon2.hash(password),
  verify: (password, hash) => argon2.verify(hash, password),
};

Requires bun add argon2 (native Node.js addon).

Pass your custom instance to createAuth the same way:

const auth = createAuth({
  secret: process.env.AUTH_SECRET!,
  cookie: cookieBridge,
  resolveUser: async (id) => db.user.findUnique({ where: { id } }),
  resolveUserByCredentials: async (creds) =>
    db.user.findUnique({ where: { email: creds.email } }),
  hash, // your custom HashInstance
});

Types

import type { HashConfig, HashInstance } from 'ideal-auth';
Navigation

Type to search…

↑↓ navigate↵ selectEsc close