The crypto Module

Hashes, Random Bytes, and Cryptographic Primitives

The crypto Module

node:crypto exposes hashing, random generation, HMACs, and key derivation. Built into every Node install.

4 min read Level 2/5 #nodejs#crypto#security
What you'll learn
  • Generate cryptographically secure random IDs
  • Hash strings with SHA-256
  • Use timing-safe equality

node:crypto exposes the low-level cryptographic primitives — secure randomness, hashing, HMACs, key derivation, ciphers.

Random IDs

For unique tokens, IDs, session secrets:

import { randomUUID, randomBytes } from "node:crypto";

randomUUID();
// 'f47ac10b-58cc-4372-a567-0e02b2c3d479'

randomBytes(16).toString("hex");
// '8e8a9b4c2d6e7f1a3b5c9d0e1f2a3b4c'

randomBytes(16).toString("base64url");
// '8E5b4c2d6e7f1a3b5c9d0E'

These are cryptographically secure. Never use Math.random() for tokens, session IDs, or anything an attacker could guess.

Hashing

import { createHash } from "node:crypto";

const hash = createHash("sha256")
  .update("hello world")
  .digest("hex");

console.log(hash);
// 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'

Use sha256md5 and sha1 are broken for security uses.

HMAC (Signing)

For signing messages with a secret:

import { createHmac } from "node:crypto";

const sig = createHmac("sha256", "secret-key")
  .update("important data")
  .digest("hex");

Common use: webhook signature verification.

Timing-Safe Compare

Comparing secrets with === leaks timing info. Use:

import { timingSafeEqual } from "node:crypto";

function verify(sigA, sigB) {
  const a = Buffer.from(sigA, "hex");
  const b = Buffer.from(sigB, "hex");
  return a.length === b.length && timingSafeEqual(a, b);
}

Passwords — Use scrypt

Never hash passwords with sha256 directly. Use a slow, salted, memory-hard function:

import { scrypt, randomBytes } from "node:crypto";
import { promisify } from "node:util";

const scryptAsync = promisify(scrypt);

async function hashPassword(password) {
  const salt = randomBytes(16).toString("hex");
  const buf = await scryptAsync(password, salt, 64);
  return `${salt}:${buf.toString("hex")}`;
}

async function verifyPassword(password, stored) {
  const [salt, hash] = stored.split(":");
  const buf = await scryptAsync(password, salt, 64);
  return buf.toString("hex") === hash;
}

For new projects, argon2 (an npm package) is even better. But scrypt is built-in and adequate.

The util Module →