Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Zozi96/hash-forge/llms.txt

Use this file to discover all available pages before exploring further.

HashManager.builder() returns a HashManagerBuilder that lets you compose a HashManager through a fluent, chainable API. While HashManager.from_algorithms() is convenient for default-parameter setups, the builder is the right tool whenever you need to tune algorithm-specific parameters, mix pre-configured hasher instances with named algorithms, or explicitly declare which algorithm should be preferred for new hashes — all without manually constructing individual hasher objects.
Prefer HashManager.builder() over HashManager.from_algorithms() whenever you need custom algorithm parameters such as a higher Argon2 time_cost, non-default bcrypt rounds, or a specific PBKDF2 iterations count. from_algorithms() always uses library defaults.

Basic Usage

Call HashManager.builder(), chain one or more .with_algorithm() calls, then call .build() to get a fully configured HashManager.
from hash_forge import HashManager

manager = (
    HashManager.builder()
    .with_algorithm("argon2")
    .with_algorithm("bcrypt")
    .build()
)

hashed = manager.hash("password123")
print(manager.preferred_hasher.algorithm)  # argon2 (first added = preferred)

Builder Methods

with_algorithm(algorithm, **kwargs)

Add an algorithm by name and pass any hasher-specific keyword arguments. The algorithm is instantiated immediately via the internal factory.
manager = (
    HashManager.builder()
    .with_algorithm("argon2", time_cost=4, memory_cost=65536, parallelism=2)
    .with_algorithm("bcrypt", rounds=14)
    .with_algorithm("pbkdf2_sha256", iterations=200_000)
    .build()
)
Supported kwargs per algorithm:
AlgorithmParameters
argon2time_cost, memory_cost, parallelism, hash_len
bcrypt / bcrypt_sha256rounds
pbkdf2_sha256 / pbkdf2_sha1iterations, salt_length
scryptwork_factor, block_size, parallelism

with_hasher(hasher)

Add a pre-configured hasher instance directly. Use this when you need to reuse an existing hasher object or when the hasher requires constructor arguments not available through with_algorithm.
from hash_forge import HashManager
from hash_forge.hashers import PBKDF2Sha256Hasher

custom_pbkdf2 = PBKDF2Sha256Hasher(iterations=300_000, salt_length=32)

manager = (
    HashManager.builder()
    .with_hasher(custom_pbkdf2)     # pre-configured instance
    .with_algorithm("bcrypt", rounds=12)
    .with_algorithm("argon2")
    .build()
)

with_preferred(algorithm)

Override which algorithm is used for new hashes. Without this call, the first algorithm added becomes the preferred one. The algorithm passed to with_preferred() must already be present in the builder.
manager = (
    HashManager.builder()
    .with_algorithm("pbkdf2_sha256")
    .with_algorithm("argon2")
    .with_algorithm("bcrypt")
    .with_preferred("argon2")   # override: argon2 used for new hashes
    .build()
)

print(manager.preferred_hasher.algorithm)  # argon2

build()

Validates the builder state and returns a configured HashManager. Raises ValueError if no hashers were added, or if with_preferred() was called with an algorithm that was not added to the builder.
manager = (
    HashManager.builder()
    .with_algorithm("argon2", time_cost=4)
    .with_algorithm("bcrypt", rounds=14)
    .with_preferred("argon2")
    .build()
)

Migration Setup

Use the builder to create a manager that hashes new passwords with Argon2 while still being able to verify legacy PBKDF2 and bcrypt hashes stored in your database.
from hash_forge import HashManager

migration_manager = (
    HashManager.builder()
    .with_algorithm("argon2")           # new hashes use this
    .with_algorithm("pbkdf2_sha256")    # can verify old PBKDF2 hashes
    .with_algorithm("bcrypt")           # can verify old bcrypt hashes
    .with_preferred("argon2")           # explicitly prefer Argon2
    .build()
)

# New registrations get Argon2
new_hash = migration_manager.hash("new_user_password")

# Legacy PBKDF2 hash still verifiable
is_valid, new_hash = migration_manager.verify_and_update(
    "old_user_password",
    legacy_pbkdf2_hash,
)
if new_hash:
    save_to_db(new_hash)  # transparently upgraded to Argon2

Web Application Setup

A typical web application configuration with a high-security primary algorithm and a legacy fallback:
from hash_forge import HashManager

web_app_manager = (
    HashManager.builder()
    .with_algorithm("argon2", time_cost=3, memory_cost=65536)  # primary
    .with_algorithm("bcrypt", rounds=12)                        # legacy fallback
    .with_preferred("argon2")
    .build()
)

# Register a new user
user_hash = web_app_manager.hash("WebAppSecurePass123!")
print(f"Registered with: {web_app_manager.preferred_hasher.algorithm}")  # argon2

# Verify on login
is_valid = web_app_manager.verify("WebAppSecurePass123!", user_hash)
print(f"Login successful: {is_valid}")  # True

Error Handling

The builder validates its state at .build() time and raises ValueError in two cases: No hashers added:
try:
    empty_manager = HashManager.builder().build()
except ValueError as e:
    print(e)
    # At least one hasher must be added to the builder
Preferred algorithm not in the builder:
try:
    invalid_manager = (
        HashManager.builder()
        .with_algorithm("bcrypt")
        .with_preferred("argon2")  # argon2 was never added!
        .build()
    )
except ValueError as e:
    print(e)
    # Preferred algorithm 'argon2' was not added to the builder

Build docs developers (and LLMs) love