Optimized bcrypt in plain JavaScript with zero dependencies, with TypeScript support.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Cryptographically secure salt generation functionality with configurable rounds for controlling computation cost. Provides both synchronous and asynchronous APIs with callback and Promise support.
Synchronously generates a cryptographically secure salt with configurable rounds.
/**
* Synchronously generates a salt.
* @param rounds Number of rounds to use, defaults to 10 if omitted (range: 4-31)
* @returns Resulting salt string in bcrypt format
* @throws Error if a random fallback is required but not set
*/
function genSaltSync(rounds?: number): string;Usage Examples:
import { genSaltSync } from "bcryptjs";
// Generate salt with default rounds (10)
const salt1 = genSaltSync();
console.log(salt1); // "$2b$10$N9qo8uLOickgx2ZMRZoMye"
// Generate salt with custom rounds
const salt2 = genSaltSync(12);
console.log(salt2); // "$2b$12$X8qo9uLOickgx2ZMRZoMye"
// Use in password hashing
const salt = genSaltSync(10);
const hash = hashSync("myPassword", salt);Asynchronously generates a cryptographically secure salt using Promises.
/**
* Asynchronously generates a salt.
* @param rounds Number of rounds to use, defaults to 10 if omitted
* @returns Promise with resulting salt
*/
function genSalt(rounds?: number): Promise<string>;Usage Examples:
import { genSalt, hash } from "bcryptjs";
// Generate salt with default rounds
const salt1 = await genSalt();
console.log(salt1); // "$2b$10$N9qo8uLOickgx2ZMRZoMye"
// Generate salt with custom rounds
const salt2 = await genSalt(12);
console.log(salt2); // "$2b$12$X8qo9uLOickgx2ZMRZoMye"
// Complete async password hashing workflow
async function hashPassword(password, rounds = 10) {
try {
const salt = await genSalt(rounds);
const hash = await hash(password, salt);
return hash;
} catch (error) {
console.error("Password hashing failed:", error);
throw error;
}
}
// Usage in Express.js route
app.post('/register', async (req, res) => {
const { username, password } = req.body;
try {
const salt = await genSalt(12);
const hashedPassword = await hash(password, salt);
const user = await createUser({
username,
hashedPassword
});
res.json({ success: true, userId: user.id });
} catch (error) {
res.status(500).json({ error: "Registration failed" });
}
});Asynchronously generates a salt with default rounds using callback API.
/**
* Asynchronously generates a salt.
* @param callback Callback receiving the error, if any, and the resulting salt
*/
function genSalt(callback: Callback<string>): void;Usage Examples:
import { genSalt } from "bcryptjs";
// Basic callback usage with default rounds
genSalt((err, salt) => {
if (err) {
console.error("Salt generation failed:", err);
return;
}
console.log("Salt generated:", salt);
// Continue with password hashing...
});Asynchronously generates a salt with specified rounds using callback API.
/**
* Asynchronously generates a salt.
* @param rounds Number of rounds to use, defaults to 10 if omitted
* @param callback Callback receiving the error, if any, and the resulting salt
*/
function genSalt(rounds: number, callback: Callback<string>): void;Usage Examples:
import { genSalt, hash } from "bcryptjs";
// Callback with custom rounds
genSalt(12, (err, salt) => {
if (err) {
console.error("Salt generation failed:", err);
return;
}
console.log("Salt generated:", salt);
// Continue with password hashing
hash("myPassword", salt, (err, hash) => {
if (err) {
console.error("Hashing failed:", err);
return;
}
console.log("Password hashed:", hash);
});
});
// Node.js callback-style user registration
function registerUser(username, password, callback) {
genSalt(10, (err, salt) => {
if (err) {
return callback(err);
}
hash(password, salt, (err, hash) => {
if (err) {
return callback(err);
}
saveUser({ username, hash }, callback);
});
});
}bcryptjs generates salts in the standard bcrypt format:
$2b$[rounds]$[salt]$2b$: bcrypt algorithm identifier (version 2b)[rounds]: Number of iterations, zero-padded (04-31)[salt]: 22-character base64-encoded random saltExamples:
$2b$10$N9qo8uLOickgx2ZMRZoMye (10 rounds)
$2b$12$X8qo9uLOickgx2ZMRZoMye (12 rounds)
$2b$04$A1qo8uLOickgx2ZMRZoMye (4 rounds - minimum)
$2b$31$Z9qo8uLOickgx2ZMRZoMye (31 rounds - maximum)// These are automatically corrected
genSaltSync(2); // Becomes 4 rounds
genSaltSync(50); // Becomes 31 rounds| Rounds | Approximate Time | Security Level | Use Case |
|---|---|---|---|
| 4 | ~1ms | Minimal | Testing only |
| 8 | ~16ms | Low | Low-security applications |
| 10 | ~100ms | Good | Standard web applications |
| 12 | ~400ms | High | Sensitive applications |
| 15 | ~3-4s | Very High | High-value targets |
| 20 | ~100s | Extreme | Long-term storage |
// Development/testing environment
const devSalt = await genSalt(4);
// Production web application
const prodSalt = await genSalt(10);
// High-security financial application
const secureSalt = await genSalt(12);
// Long-term password storage
const archivalSalt = await genSalt(15);bcryptjs uses the following sources for cryptographically secure randomness:
setRandomFallback)// If neither Web Crypto nor Node.js crypto is available
import { setRandomFallback } from "bcryptjs";
// Set a cryptographically secure fallback
setRandomFallback((length) => {
// Return array of `length` cryptographically secure random bytes
// This is critical for security - must use secure random source!
return secureRandomBytes(length);
});// Good: Generate new salt for each password
async function hashMultiplePasswords(passwords) {
const hashes = [];
for (const password of passwords) {
const salt = await genSalt(10); // New salt each time
const hash = await hash(password, salt);
hashes.push(hash);
}
return hashes;
}
// Bad: Reusing the same salt (vulnerable to rainbow tables)
async function hashMultiplePasswordsBad(passwords) {
const salt = await genSalt(10); // Same salt for all
const hashes = [];
for (const password of passwords) {
const hash = await hash(password, salt); // DON'T DO THIS
hashes.push(hash);
}
return hashes;
}// Synchronous error handling
try {
const salt = genSaltSync(10);
console.log("Salt generated:", salt);
} catch (error) {
if (error.message.includes("random fallback")) {
console.error("No secure random source available");
// Set up fallback or use different environment
} else {
console.error("Salt generation failed:", error);
}
}
// Asynchronous Promise error handling
try {
const salt = await genSalt(10);
console.log("Salt generated:", salt);
} catch (error) {
console.error("Salt generation failed:", error);
}
// Callback error handling
genSalt(10, (err, salt) => {
if (err) {
console.error("Salt generation failed:", err);
return;
}
console.log("Salt generated:", salt);
});// Pre-generate salts for batch operations
async function preGenerateSalts(count, rounds = 10) {
const salts = [];
const promises = [];
for (let i = 0; i < count; i++) {
promises.push(genSalt(rounds));
}
return Promise.all(promises);
}
// Use appropriate rounds for your use case
const rounds = process.env.NODE_ENV === 'production' ? 12 : 8;
const salt = await genSalt(rounds);