Skip to content

imjlk/cloudflare-auth-hasher-template

Repository files navigation

Cloudflare Auth Hasher Template

CI Deploy to Cloudflare

Private password hashing template for Cloudflare Workers using WorkerEntrypoint RPC, Argon2id, and a Rust/Wasm kernel.

What This Is

This repository ships a root-deployable Worker that is meant to be called from another Worker through a private service binding.

  • hashPassword(password: string): Promise<string>
  • verifyPassword(hash: string, password: string): Promise<boolean>
  • GET / metadata and health by default
  • Better Auth legacy salt:key scrypt verification compatibility
  • gradual upgrade helpers such as verifyAndMaybeRehash()

The public HTTP surface stays intentionally small. The Worker is designed to be an internal password-hashing service, not a public hash API.

Who Should Use This

Use this template if you:

  • run authentication logic on Cloudflare Workers
  • want password hashing behind private service bindings instead of public HTTP
  • need an incremental migration path from older Better Auth salt:key scrypt hashes
  • want a TypeScript Worker shell while keeping the hashing kernel in Rust/Wasm

Why Private RPC Instead Of Public HTTP

Cloudflare recommends Worker-to-Worker communication through service bindings. This template follows that pattern with WorkerEntrypoint RPC so your application Worker can call the hasher without exposing password hashing over a public route.

  • caller Worker traffic stays on Cloudflare's internal service-binding path
  • the hasher Worker keeps a narrow public surface
  • the root Worker API is stable and easy to wrap from other Workers

60-Second Quick Start

  1. Install dependencies.
npm install
  1. Authenticate Wrangler.
npx wrangler login
npx wrangler whoami
  1. Validate the template.
npm run typecheck
npm run check

Run the full Rust-backed suite when the Rust toolchain is available locally:

npm test
  1. Deploy the Worker.
npm run deploy
  1. Bind it from your application Worker.

For cross-account deploys, set CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, or copy mise.local.example.toml to mise.local.toml and load it with mise.

Better Auth Example

The Better Auth adapter keeps Worker binding lookup isolated from framework-specific code. Use the adapter for the primary hash/verify flow, then use verifyAndMaybeRehash() after successful login to migrate older or lower-cost hashes.

import { createAuthPasswordHasher } from "@cloudflare-auth-hasher/better-auth-adapter";
import {
  STANDARD_2026Q1_PRESET,
  resolveAuthHasherBinding,
  verifyAndMaybeRehash
} from "@cloudflare-auth-hasher/client";

const hasher = createAuthPasswordHasher(event, {
  fallback: {
    hashPassword: fallbackHashPassword,
    verifyPassword: fallbackVerifyPassword
  }
});

const verified = await hasher.verify({ hash: storedHash, password });
if (verified) {
  const binding = resolveAuthHasherBinding(event.platform?.env);
  if (binding) {
    await verifyAndMaybeRehash(binding, storedHash, password, {
      targetPreset: STANDARD_2026Q1_PRESET
    });
  }
}

See examples/better-auth-worker for a minimal Worker-shaped example.

Architecture

flowchart LR
    caller["Caller Worker"] --> binding["Private Service Binding"]
    binding --> rpc["WorkerEntrypoint RPC"]
    rpc --> hasher["Auth Hasher Worker"]
    hasher --> kernel["Rust/Wasm Argon2id Kernel"]
Loading

Presets And Migration

Canonical preset IDs:

  • standard-2026q1
    • default
    • repository OWASP-aligned floor
    • Argon2id 12288 KiB / t=3 / p=1 / 32 bytes
    • uses one of OWASP's detailed equivalent Argon2id configurations rather than a weaker "almost OWASP" compromise
  • free-tier-fallback-2026q1
    • Workers Free fallback when the higher-cost preset is not operationally viable
    • not an OWASP-equivalent recommendation
    • Argon2id 4096 KiB / t=1 / p=1 / 32 bytes

Legacy aliases are still accepted for input compatibility:

  • standard-recommended -> standard-2026q1
  • free-safe-probe -> free-tier-fallback-2026q1

If you start on the lower-cost preset and later move to standard-2026q1, older hashes still verify because the stored Argon2 PHC string carries its own parameters. Use verifyAndMaybeRehash() or needsPasswordRehash() to replace weaker hashes after successful login.

AUTH_HASHER_* Semantics

Variable Affects Notes
AUTH_HASHER_PRESET_ID build + metadata selects the canonical preset label and default Argon2 profile
AUTH_HASHER_ARGON2_* build + metadata changes Rust/Wasm hash output and the metadata Argon2 fields, so they should stay aligned
AUTH_HASHER_ENABLE_METADATA_ROUTE runtime only hides GET / metadata and makes the route return 404
AUTH_HASHER_WORKER_CPU_MS deploy config only injects Wrangler limits.cpu_ms; it does not change hash parameters

Plan Guidance

Plan Preset Observed benchmark signal Recommendation
Workers Paid or higher-budget deployment standard-2026q1 winner baseline from the higher-cost finalist comparison preferred default
Workers Free or tightly constrained budget free-tier-fallback-2026q1 lower-cost fallback stabilized the test account after reducing cost use only as a platform fallback

Security And Operations

  • GET / exists for metadata, health checks, and deploy verification. You can disable it with AUTH_HASHER_ENABLE_METADATA_ROUTE=false.
  • metadata includes the active algorithm, template version, and tracked artifact checksum so deploy verification can be done with a single request.
  • Hashing is not exposed through public HTTP routes. The intended path is private RPC through service bindings.
  • The template does not intentionally log plaintext passwords or password hashes. If you add application logs, keep credentials and hashes out of logs.
  • Observability defaults are enabled so first deploys are debuggable. Harden or reduce persistence to match your own policy.
  • workers_dev: true is enabled by default for easier first deploys. Disable it and map a custom route when you move to a tighter production posture.

More detail: docs/security-and-operations.md

When Not To Use This

Do not use this template if:

  • you want a public password hashing API
  • the Workers Free fallback preset is too weak for your threat model and you cannot move to a higher-budget plan
  • you want an npm library instead of a private Worker service

Maintenance Policy

This template should be reviewed at least quarterly.

  • update compatibility_date
  • review wrangler, TypeScript, and Rust dependencies
  • rebuild the Rust/Wasm kernel and confirm there is no artifact drift
  • re-evaluate preset guidance when Cloudflare plan limits materially change

Contributor workflow: CONTRIBUTING.md

Benchmark History

This root template was promoted from the benchmark workspace.

  • ts-rust-wasm beat rust-full in the higher-cost finalist comparison
  • the Free-tier fallback preset stabilized both finalists on the test account, but that fallback is a platform accommodation, not the security baseline

Full benchmark history:

Repository Layout

src/                       # root Worker entrypoint and Wasm glue
crates/hash-core/          # shared Rust hashing logic
crates/rust-wasm-kernel/   # raw Wasm kernel wrapper
packages/contracts/        # shared RPC and preset contracts
packages/client/           # binding helpers and rehash helpers
packages/better-auth-adapter/
examples/
docs/

The workspace packages are internal template building blocks.

  • they remain private: true
  • they are not published as standalone npm packages from this repository form

References

About

Private password hashing template for Cloudflare Workers using WorkerEntrypoint RPC, Argon2id, and a Rust/Wasm kernel.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors