CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-bcryptjs

Optimized bcrypt in plain JavaScript with zero dependencies, with TypeScript support.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

password-verification.mddocs/

Password Verification

Password verification functionality for comparing plain text passwords against bcrypt hashes. Provides both synchronous and asynchronous APIs with optional progress tracking for time-intensive operations.

Capabilities

Synchronous Password Comparison

Synchronously tests a password against a bcrypt hash.

/**
 * Synchronously tests a password against a hash.
 * @param password Password to test
 * @param hash Hash to test against
 * @returns true if matching, otherwise false
 */
function compareSync(password: string, hash: string): boolean;

Usage Examples:

import { compareSync } from "bcryptjs";

// Basic password verification
const hash = "$2b$10$N9qo8uLOickgx2ZMRZoMye2Z8WSdtXvKLhXfV.O/JZ4MYxvmq4dS6";
const isValid = compareSync("myPassword", hash);
console.log(isValid); // true or false

// Login verification function
function verifyLogin(username, password, storedHash) {
  try {
    const isValid = compareSync(password, storedHash);
    if (isValid) {
      console.log(`Login successful for ${username}`);
      return true;
    } else {
      console.log(`Invalid password for ${username}`);
      return false;
    }
  } catch (error) {
    console.error("Password verification failed:", error);
    return false;
  }
}

Asynchronous Password Comparison (Promise)

Asynchronously tests a password against a hash using Promises.

/**
 * Asynchronously tests a password against a hash.
 * @param password Password to test
 * @param hash Hash to test against
 * @returns Promise resolving to boolean result
 */
function compare(password: string, hash: string): Promise<boolean>;

Usage Examples:

import { compare } from "bcryptjs";

// Basic async verification
const hash = "$2b$10$N9qo8uLOickgx2ZMRZoMye2Z8WSdtXvKLhXfV.O/JZ4MYxvmq4dS6";
const isValid = await compare("myPassword", hash);
console.log(isValid); // true or false

// Async login verification
async function verifyLoginAsync(username, password, storedHash) {
  try {
    const isValid = await compare(password, storedHash);
    if (isValid) {
      console.log(`Login successful for ${username}`);
      return { success: true, user: username };
    } else {
      console.log(`Invalid password for ${username}`);
      return { success: false, error: "Invalid credentials" };
    }
  } catch (error) {
    console.error("Password verification failed:", error);
    return { success: false, error: "Verification failed" };
  }
}

// Express.js middleware example
app.post('/login', async (req, res) => {
  const { username, password } = req.body;
  const user = await getUserByUsername(username);
  
  if (!user) {
    return res.status(401).json({ error: "Invalid credentials" });
  }
  
  const isValid = await compare(password, user.hashedPassword);
  if (isValid) {
    // Generate JWT token or session
    res.json({ success: true, token: generateToken(user) });
  } else {
    res.status(401).json({ error: "Invalid credentials" });
  }
});

Asynchronous Password Comparison (Callback)

Asynchronously tests a password against a hash using callback-based API with optional progress tracking.

/**
 * Asynchronously tests a password against a hash.
 * @param password Password to test
 * @param hash Hash to test against
 * @param callback Callback receiving the error, if any, and the result
 * @param progressCallback Optional callback for progress updates (0.0 - 1.0)
 */
function compare(
  password: string,
  hash: string,
  callback?: Callback<boolean>,
  progressCallback?: ProgressCallback
): void;

Usage Examples:

import { compare } from "bcryptjs";

// Basic callback usage
const hash = "$2b$10$N9qo8uLOickgx2ZMRZoMye2Z8WSdtXvKLhXfV.O/JZ4MYxvmq4dS6";
compare("myPassword", hash, (err, result) => {
  if (err) {
    console.error("Comparison failed:", err);
    return;
  }
  console.log("Password is valid:", result);
});

// With progress callback for high-round hashes
compare("myPassword", highRoundHash, 
  (err, result) => {
    if (err) {
      console.error("Comparison failed:", err);
      return;
    }
    console.log("Verification completed:", result);
  },
  (progress) => {
    console.log(`Verification progress: ${Math.round(progress * 100)}%`);
  }
);

// Node.js callback-style authentication
function authenticateUser(username, password, callback) {
  getUserHash(username, (err, storedHash) => {
    if (err) {
      return callback(err);
    }
    
    compare(password, storedHash, (err, isValid) => {
      if (err) {
        return callback(err);
      }
      
      callback(null, isValid);
    });
  });
}

Security Best Practices

Constant-Time Comparison

bcryptjs implements constant-time comparison to prevent timing attacks. The verification time remains consistent regardless of whether the password matches or not.

Hash Validation

The comparison functions validate the hash format before processing:

// Valid bcrypt hash format
const validHash = "$2b$10$N9qo8uLOickgx2ZMRZoMye2Z8WSdtXvKLhXfV.O/JZ4MYxvmq4dS6";

// Invalid formats will cause comparison to return false
const invalidHash1 = "plaintext"; // Not a hash
const invalidHash2 = "$2a$10$invalid"; // Malformed hash
const invalidHash3 = ""; // Empty string

// All these will return false safely
console.log(compareSync("password", invalidHash1)); // false
console.log(compareSync("password", invalidHash2)); // false
console.log(compareSync("password", invalidHash3)); // false

Error Handling Patterns

// Synchronous error handling
function safeCompareSync(password, hash) {
  try {
    return compareSync(password, hash);
  } catch (error) {
    console.error("Password comparison failed:", error);
    return false; // Fail securely
  }
}

// Asynchronous error handling
async function safeCompareAsync(password, hash) {
  try {
    return await compare(password, hash);
  } catch (error) {
    console.error("Password comparison failed:", error);
    return false; // Fail securely
  }
}

// Callback error handling
function safeCompareCallback(password, hash, done) {
  compare(password, hash, (err, result) => {
    if (err) {
      console.error("Password comparison failed:", err);
      return done(null, false); // Fail securely
    }
    done(null, result);
  });
}

Performance Considerations

  • Round Impact: Verification time matches the rounds used during hashing
  • Asynchronous Benefits: Non-blocking execution for high-round hashes
  • Progress Tracking: Available for operations exceeding 100ms
  • Caching: Consider caching successful authentications with session tokens

Common Integration Patterns

// Express.js authentication middleware
const authenticateToken = async (req, res, next) => {
  const { password } = req.body;
  const user = req.user; // From previous middleware
  
  try {
    const isValid = await compare(password, user.hashedPassword);
    if (!isValid) {
      return res.status(401).json({ error: "Invalid password" });
    }
    next();
  } catch (error) {
    res.status(500).json({ error: "Authentication failed" });
  }
};

// React login form handler
const handleLogin = async (username, password) => {
  try {
    const response = await fetch('/api/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ username, password })
    });
    
    if (response.ok) {
      const data = await response.json();
      localStorage.setItem('token', data.token);
      return { success: true };
    } else {
      return { success: false, error: 'Invalid credentials' };
    }
  } catch (error) {
    return { success: false, error: 'Login failed' };
  }
};

docs

index.md

password-hashing.md

password-verification.md

salt-generation.md

utility-functions.md

tile.json