Skip to content
Meeko
Type to search the guides and the API reference. Open it from any page with / or Ctrl K; move with the arrow keys and open a result with Enter.
Get started

Contents

On this page

needsRehash

Indicates whether a password hash needs recalculating with the current hashPassword parameters, to update it after a successful login.

utility Since 1.2.0 @meekojs/meeko/password Source code
ts
import { needsRehash } from "@meekojs/meeko/password";

needsRehash(hash) tells you whether a stored hash needs recalculating with the current hashPassword parameters: its cost (N, r, p), salt or key is smaller than the current values, or its format is invalid. It is synchronous and does not calculate any hash.

Use it immediately after a successful login: that is the only time the server has the plaintext password to calculate the new hash.

Usage#

ts
import { hashPassword, needsRehash, verifyPassword } from "@meekojs/meeko/password";

if (await verifyPassword(input.password, user.passwordHash) && needsRehash(user.passwordHash)) {
  await db.users.update(user.id, { passwordHash: await hashPassword(input.password) });
}

Type#

ts
function needsRehash(hash: string): boolean

Parameters#

Parameter Type Default Description
hash string required The stored hash.

Return value#

true if you should store a new hash; false if the hash already uses the current parameters (or larger ones). It never throws: text that is not a Meeko hash returns true.

Hash Result
From hashPassword in this version (scrypt$131072$8$1$…) false
scrypt$16384$8$1$…, with a lower cost true
bcrypt$…, $2b$10$… or any other text true

Examples#

In the login procedure#

ts
// server/rpc/auth/login.ts
import { ApiError, defineRpc } from "@meekojs/meeko/server";
import { hashPassword, needsRehash, verifyPassword } from "@meekojs/meeko/password";
import { loginInput, loginOutput } from "../../../shared/schemas/auth";

export default defineRpc({
  input: loginInput,
  output: loginOutput,
  origin: "required",
  rateLimit: { limit: 5, window: "5m" },
  handler: async ({ input, context }) => {
    const user = await context.services.db.users.byEmail(input.email);
    if (!user || !(await verifyPassword(input.password, user.passwordHash))) throw new ApiError("INVALID_CREDENTIALS", 401);
    if (needsRehash(user.passwordHash)) {
      context.platform.waitUntil(hashPassword(input.password).then((passwordHash) => context.services.db.users.update(user.id, { passwordHash })));
    }
    await context.session.create({ userId: user.id });
    return { ok: true };
  },
});

waitUntil lets the new hash be calculated and stored without delaying the response.

Checking how many accounts remain to migrate#

ts
import { needsRehash } from "@meekojs/meeko/password";

export function pendingRehash(hashes: readonly string[]): number {
  return hashes.filter(needsRehash).length;
}

Common mistakes#

Recalculating without verification#

Without verifyPassword, the new hash would be calculated from an unchecked password: anyone could change another account's password, without any error.

Incorrectts
if (needsRehash(user.passwordHash)) await save(user.id, await hashPassword(input.password));
Correctts
if (await verifyPassword(input.password, user.passwordHash) && needsRehash(user.passwordHash)) await save(user.id, await hashPassword(input.password));

Calling it with await expecting a promise#

needsRehash is synchronous. An await is unnecessary but does not fail; the mistake is treating its result as a promise.

Incorrectts
needsRehash(hash).then((stale) => stale && rehash());

meeko check reports TS2339: Property 'then' does not exist on type 'boolean'.

Correctts
if (needsRehash(hash)) await rehash();

Notes#

  • Cost. It calculates nothing: it reads the hash parameters. You can call it on every login.
  • Migrations. With verifyPassword and another library for old hashes, needsRehash returns true for any non-Meeko hash, so the account migrates on its next login.
  • Runtimes. Server only (Node, Bun and Deno), like the rest of @meekojs/meeko/password.

Was this page helpful?

Add a comment

It is sent when you choose “Yes” or “No”. Only the page, your answer and the comment are stored: no cookies and no personal data.

0 of 2000 characters

Edit on GitHub: docs/en/reference/utils/needsrehash.md