Hash passwords with bcrypt
Hash and verify passwords using bcrypt with a configurable cost factor. Designed to be slow on purpose — resistant to brute force. Runs locally in your browser.
bcrypt cost factor: every +1 doubles the work. Recommended baseline.
Hash will appear here…
How to hash and verify with bcrypt: a complete step-by-step guide
bcrypt is an adaptive password-hashing function based on the Blowfish cipher, designed by Provos & Mazières in 1999. It applies a per-password salt and a tunable cost factor — every increment doubles the work — so the algorithm stays slow even as hardware accelerates. This tool runs the bcryptjs library entirely in your browser; nothing about the password or hash ever leaves your device. Bcrypt is one of three OWASP-approved password hashes, alongside Argon2id and scrypt.
- 01
Pick hash or verify mode
Switch to Hash to derive a new bcrypt hash from a plaintext password — the normal signup flow. Switch to Verify to check a candidate password against an existing bcrypt hash — the login flow.
Bcrypt is one-way: there is no decryption. To "reset" a forgotten password you must accept a new one and re-hash. Compare bcrypt against other slow KDFs with the Argon2, scrypt, and PBKDF2 tools.
one-wayOWASPsignuploginKDFmode · selectorhashHash · Verify
mode setbcryptjs · ready - 02
Tune the cost factor (work factor)
The cost factor is a power-of-two exponent: cost
nmeans2^nBlowfish key-schedule iterations. Each +1 doubles wall-clock time. Cost 10 is the lowest defensible value; 12 is the modern baseline; 14+ is for high-value secrets willing to spend hundreds of milliseconds per login.Target ~100-300 ms per hash on your production hardware. Re-benchmark every 18-24 months — what was slow in 2020 is trivial in 2026. Bcrypt's salt is 128 bits, generated automatically per call.
cost factor2^nsalt roundsOWASP 2024benchmarkrounds · cost12cost 12 → 2^12 = 4096 iterations ~250ms
balancedOWASP baseline - 03
Generate the salted hash
bcrypt emits a self-describing string in Modular Crypt Format:
$2b$<cost>$<22-char-salt><31-char-hash>— total 60 characters. The$2b$prefix identifies the algorithm variant;$2a$and$2y$are older but still verifiable.Because the cost and salt live inside the hash, there's nothing extra to store — write the whole 60-char string to your users table and you're done.
$2b$Modular Crypt60 charsself-describingsalt embeddedoutput · bcrypt hash60 chars$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW
60 B · 1 lineMCF · ready - 04
Verify on next login and rotate cost
To verify, call
bcrypt.compare(candidate, storedHash)— bcryptjs parses the cost and salt out of the stored hash, re-hashes the candidate with identical parameters, and does a constant-time comparison. On match, optionally re-hash with a higher cost if you've bumped your baseline since signup.Pair bcrypt with HTTPS for transport, rate-limiting for online attacks, and an HMAC pepper if your threat model includes database leaks separate from application-secret leaks.
bcrypt.compareconstant-timerehashpepperprivacy-firstverify · resultmatch✓ Match — password is correct ✓ Constant-time compare ✓ 100% client-side
verified0 outbound
Encoding without surprises
Always UTF-8 first
Use TextEncoder / TextDecoder for bytes ↔ string conversion. btoa alone breaks on non-ASCII.
URL-safe vs standard Base64
Standard uses +, /, =; URL-safe swaps to -, _, no padding. Don’t mix them.
Hashes aren’t passwords
SHA-256 is fast; that’s good for fingerprints, bad for passwords. Use bcrypt / argon2 for credentials.
Watch padding rules
Some decoders are strict about = padding, others auto-pad. If round-trips fail at exactly 1 or 2 bytes, check padding.
Use Web Crypto for keys
Generate cryptographic keys via crypto.subtle, never Math.random. The latter is predictable.
JWT decode ≠ verify
Decoding a JWT just splits and base64-decodes. Verification needs the issuer’s public key / shared secret.
When to use bcrypt
Password storage, login flows, credential rotation.
User signup
Hash incoming passwords before writing them to the database. Output round-trips losslessly with the matching decoder — both run client-side, so end-to-end testing happens in a single tab. Encoding flows through TextEncoder for predictable UTF-8 semantics.
RFC-compliantLogin verification
Compare candidate passwords against stored hashes. Web Crypto's subtle.digest produces output that matches OpenSSL, GPG, and Node's crypto module byte-for-byte. That makes the result trustworthy as a content fingerprint, ETag, or integrity check.
OpenSSL-matchedMigrate from MD5
Re-hash legacy passwords on next login. Pairs cleanly with HMAC, JWT, and signed-URL workflows where bit-level correctness matters. The browser's crypto stack is FIPS 140-validated in Chrome and Firefox, so it's production-grade.
losslessAPI tokens
Hash long-lived API tokens at rest. Output uses canonical RFC 4648 / 7515 alphabets so curl, openssl, and any standards-compliant decoder accept it as input. URL-safe variants drop padding for tokens that travel in query strings.
byte-identicalTuning cost
Bump the cost as hardware gets faster. Heavy hashing runs through useMemo so large inputs don't block typing. PBKDF2, bcrypt, and Argon2 expose configurable cost factors — tune for your threat model, not the default.
spec-gradeCross-platform
bcryptjs interoperates with native bcrypt libraries. Same input plus same options always yields identical bytes. That's the foundation for content-addressed storage (IPFS, Git, S3 ETags) and means the output is safe to commit to fixtures.
production-readyFrequently asked questions
Something missing?
Tell us what you need. We ship the top requests every two weeks.