Hashes, Random Bytes, and Cryptographic Primitives
The crypto Module
node:crypto exposes hashing, random generation, HMACs, and key derivation. Built into every Node install.
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 sha256 — md5 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.