An htpasswd file is how Apache and nginx guard a directory with a username and password, and each line of it is a username, a colon and a password hash. The hash is the part that matters: the file usually sits inside the site's own directory, so anything reversible in it is not protection at all. This produces a bcrypt entry, which is what the htpasswd command itself writes with its -B option.
The cost is fixed at 10, the default that Apache uses, and there is no control for it here. The library emits the identifier $2a$ and the prefix is rewritten to $2y$, which is the same algorithm — the newer identifier was introduced to mark implementations free of an old sign-extension bug that this one never had — and $2y$ is what an administrator expects to see in the file.
Getting the file right
-
A username cannot contain a colon:
it is the field separator, so a colon produces a line that cannot be parsed. It is refused here rather than written out.
-
Put the file outside the web root where you can:
even hashed, a password file is not something to serve. If it must live inside, make sure the server is configured to refuse requests for it.
-
Bcrypt reads only the first 72 bytes:
a longer password is silently truncated, so it is refused here rather than producing an entry weaker than it appears.
-
Basic authentication sends the password on every request:
it is protected only by the connection, so this belongs behind HTTPS and nowhere else.
A real hash, not something that merely looks encoded
Every line of an htpasswd file is a username, a colon, and a password hash, and the hash is the part that actually matters — the file itself usually sits inside the site's own directory, so anything reversible written there offers no protection at all. Base64 is sometimes mistaken for a hash because the output looks similarly unreadable, but it is only an encoding: it reverses in a single step, and a password stored that way is effectively stored in the clear. The [msm_tool slug="htpasswd-generator"] produces a genuine bcrypt entry, the same format the `htpasswd` command itself writes with its `-B` option.
The cost is fixed at ten
There is no cost control here; every entry is generated at cost 10, which is Apache's own default. Anyone who wants a different cost factor for a different purpose has the dedicated bcrypt tool, which exposes that control directly — this one is built specifically to produce what an `.htpasswd` file expects, not a general-purpose hash.
Why the hash starts with $2y$ rather than $2a$
Both identifiers name the same algorithm. The newer `$2y$` prefix exists to mark implementations that are free of an old sign-extension bug in certain non-ASCII passwords — a bug this implementation never had — and it is rewritten to that prefix regardless, because `$2y$` is what Apache writes itself and what an administrator opening the file expects to see.
A colon in the username breaks the file
The colon is the field separator between username and hash, so a username containing one would produce a line the file format cannot parse correctly. That case is refused outright rather than written out and left to fail quietly later.
Where the file should actually live
Placing `.htpasswd` outside the web root is the safer choice wherever the hosting setup allows it, since even a properly hashed password file is not something meant to be served to a browser. Where it has to sit inside the web root, the server needs an explicit rule blocking direct requests for it — the file being hashed does not make serving it harmless.
Basic authentication needs HTTPS, not just a hash
Basic authentication sends the password on every single request, protected by nothing but the connection it travels over. A carefully generated hash in the file does not change that; the credential is only as safe as the HTTPS in front of it.