or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.mdpassword-hashing.mdpassword-verification.mdsalt-generation.mdutility-functions.md
tile.json

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' };
  }
};