How to Verify a BCrypt Hash
BCrypt verification is the operation that runs when a user logs in. It takes the plaintext password they entered and the stored hash, and determines whether they match. When this fails for a user who should be able to log in, the problem is almost always in how the hash was stored or compared — not in BCrypt itself.
How BCrypt verification works
BCrypt hashes embed the salt used to create them. Verification extracts the salt from the stored hash, re-hashes the input password using that same salt, and compares the result to the stored hash. If they match, the password is correct.
This means you don't need to store the salt separately — it's already in the hash. It also means you can never "decrypt" a BCrypt hash; you can only verify against it by providing the original plaintext password.
Why verification fails for a valid password
Encoding mismatch. The hash was stored as bytes in the database but retrieved as a string (or vice versa). BCrypt expects either consistently bytes or consistently strings. Mixing them causes verification to fail silently — no error, just false.
Column truncation. BCrypt hashes are 60 characters long. If the database column is defined as VARCHAR(50) or similar, the hash gets silently truncated when stored. The truncated hash will never match anything. Verify your column length is at least 60 characters (or use CHAR(60)).
Double hashing. If the application hashes the password before sending it to the database layer, and the database layer hashes it again, the stored hash is of the already-hashed password. When a user logs in, only the first hash is applied, and verification fails. Check for password hashing at multiple layers in the code.
Trailing whitespace or newlines. Some forms or API clients add a trailing newline to input. "password
" and "password" hash to completely different values. Trim input before hashing.
Upgrading cost factor
As hardware gets faster, the cost factor needs to increase to maintain the same security properties. Most applications handle this by re-hashing the password with the new cost factor at login time — once the user provides their password, verify against the old hash, then immediately re-hash with the new cost factor and store the updated hash. This migrates users transparently as they log in.