Use this Worker through a private Cloudflare service binding and WorkerEntrypoint RPC.
References:
The Worker exposes:
hashPassword(password: string): Promise<string>verifyPassword(hash: string, password: string): Promise<boolean>
Shared contracts live in packages/contracts.
In the calling Worker, add a service binding that points at the deployed hasher Worker name.
Replace "cloudflare-auth-hasher-template" with your deployed Worker name.
remote: true matters during local wrangler dev because it lets the local caller reach the deployed hasher Worker over Cloudflare's private service-binding path.
The recommended application flow is:
- verify the stored hash
- detect whether the stored hash is below the current target preset
- replace it only after successful verification
That is what verifyAndMaybeRehash() does.
import type { AuthHasherBinding } from "@cloudflare-auth-hasher/contracts";
import {
STANDARD_2026Q1_PRESET,
ensureAuthHasherBinding,
verifyAndMaybeRehash
} from "@cloudflare-auth-hasher/client";
type Env = {
AUTH_HASHER: AuthHasherBinding;
};
async function verifyPasswordAndUpgrade(
env: Env,
storedHash: string,
password: string,
persistNextHash: (nextHash: string) => Promise<void>
): Promise<boolean> {
const hasher = ensureAuthHasherBinding(env, "AUTH_HASHER");
const result = await verifyAndMaybeRehash(hasher, storedHash, password, {
targetPreset: STANDARD_2026Q1_PRESET,
persistUpdatedHash: persistNextHash
});
return result.verified;
}Returned fields:
verifiedneedsRehashrehashedupdatedHashreasons
reasons tells you why the stored hash was considered below the current target. That includes legacy Better Auth scrypt hashes and lower-cost Argon2 hashes.
updatedHash is meant for server-side persistence only. Do not send the replacement hash back to clients in public responses.
verifyAndMaybeRehash() assumes the deployed hasher Worker is already configured to the same target preset you pass in.
If the Worker still emits a weaker hash than the requested target preset, the helper throws instead of silently persisting another below-target hash.
That guard exists to keep Free-to-Paid migration explicit:
- upgrade the hasher Worker preset first
- verify the deployed metadata through
GET / - then let callers persist stronger hashes on login
See examples/rpc-caller-worker for a minimal Worker that:
- resolves the
AUTH_HASHERbinding - accepts a login-style request
- calls
verifyAndMaybeRehash() - persists replacement hashes server-side
- returns only non-sensitive upgrade status fields
If your app uses Better Auth, start from packages/better-auth-adapter and examples/better-auth-worker.
Recommended Better Auth shape:
- use
createAuthPasswordHasher()for the primary Better Auth hash/verify flow - resolve the binding directly after successful login
- call
verifyAndMaybeRehash()so legacy or lower-cost hashes are replaced gradually
GET /returns metadata for health checks and deploy verification by default- set
AUTH_HASHER_ENABLE_METADATA_ROUTE=falseto disable the metadata route and makeGET /return404 - metadata includes
algorithm, templateversion, andartifactSourceChecksumfor deploy verification - runtime metadata always emits canonical preset IDs such as
standard-2026q1, even if you configured a legacy alias standard-2026q1is the template's OWASP-aligned floorfree-tier-fallback-2026q1is a constrained Workers Free fallback, not a general security recommendation- on Workers Paid,
AUTH_HASHER_WORKER_CPU_MScan be used at deploy time to injectlimits.cpu_ms
{ "$schema": "../../node_modules/wrangler/config-schema.json", "name": "my-app-worker", "main": "src/index.ts", "compatibility_date": "2026-03-10", "compatibility_flags": ["nodejs_compat"], "services": [ { "binding": "AUTH_HASHER", "service": "cloudflare-auth-hasher-template", "remote": true } ] }