htpasswd Generator

Generate an .htpasswd line with a SHA-1 hash computed in your browser, get a ready .htaccess block for Apache 2.4 with Require valid-user, plus the server command.

Everything runs in your browser — your data is never sent to any server.

Why you need an .htpasswd generator

An .htpasswd file is a plain text file holding usernames and password hashes for Apache basic authentication. It locks down a directory, a page or an API with a single line, Require valid-user, and no code of your own. The catch is that the file cannot be improvised: the password has to be hashed, and on a server that normally means Apache itself. If you have no htpasswd Apache to hand and the task is urgent, the remaining option is to compute the hash in a browser, which is exactly what this htpasswd generator does. You get the file line and a ready .htaccess block that can be dropped in place and start working. One caveat right away: what gets computed in the browser is SHA-1, while the right choice for a new site is bcrypt, and that is computed on the server.

What the generator does

  • Username and password entry with checks: a colon or a space in the username is rejected
  • SHA-1 computed in the browser through Web Crypto, handed over as a «username:{SHA}…» line — the same algorithm the SHA-1 generator uses
  • A bcrypt mode that gives you the ready htpasswd command, because counting it in a browser is expensive
  • A ready .htaccess block for Apache 2.4 with Require valid-user and the path to the password file
  • One-click copying of the line, the command and the block, plus a password generator for the password itself

How to get a working password file

  1. Type the username and the password, and use the button next to the field if you want a random one
  2. Pick the algorithm: SHA-1 is computed here, bcrypt is computed on the server
  3. Press «Generate the htpasswd line» and copy the result
  4. Put the line into an .htpasswd file on the server and add the .htaccess block from the section below

What an .htpasswd line is made of

The format is about as simple as it gets: one line per user, username, colon, hash, end of line. Lines starting with a hash sign are treated as comments and skipped. The line itself is not encrypted, it is hashed, and the algorithm is declared by the prefix. The {SHA} scheme means SHA-1 written in base64 — the same thing the SHA-1 tool produces, and there is a separate page for several hashes at once: exactly 28 characters after the prefix, which is 20 bytes of hash. The $apr1$ scheme is Apache MD5, a crypt variant with its own salt and a thousand iterations. The $2y$, $2a$ and $2b$ schemes are bcrypt, where the salt and the cost are built into the string. Verification happens on the server: Apache reads the file, finds the line by username, applies the declared algorithm to the password that was typed, and compares the results.

Password formats Apache understands

SchemeWhat the line looks likeComment
{SHA}admin:{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=SHA-1 in base64, no salt, an outdated format
$apr1$admin:$apr1$<salt>$<hash>Apache MD5, its own salt and a thousand iterations
$2y$admin:$2y$05$<22 salt chars><31 hash chars>bcrypt, the cost is set with the -C key
$2a$admin:$2a$05$<salt><hash>bcrypt, the older variant, still found in some PHP builds
$2b$admin:$2b$05$<salt><hash>bcrypt, the current variant with the code fixes applied
Clear textadmin:secretApache does not count this as a password, and the line leaks by itself
Comment# a noteLines starting with a hash sign are skipped when the file is read

The rows for $2y$, $2a$ and $2b$ show the structure of a line rather than a real hash: only a result computed on the server can be substituted there.

Where htpasswd earns its keep

The first scenario is locking down a service area of a site: statistics, backups, drafts, an admin panel, an API with a key. The second is protecting a directory on static hosting, where there is no PHP and no control panel and .htaccess is the only mechanism available. The third is handing out temporary access to material for a client or a contractor for a few days and revoking it later with a single edit to the file. The fourth is an old application that expects a password file in a particular format, produced by a particular program rather than by Apache itself.

There is also the server-side variant of htpasswd Apache, and the rules that go with it are spelled out in the full .htaccess guide: creating an account for a script or for CI that reaches the site over basic authentication. The password file then becomes a machine secret and has to be stored with the same care as any other credential. In that case it is usually better to generate the file on the server and hand it to a secrets manager than to keep it in a repository. When the account itself is a machine identity rather than a person, what a UUID is is worth reading first. The .htaccess generator is the companion tool here: it assembles the redirect rules, the HTTPS switch and the access blocks that usually live in the same file.

  • Locking down a service directory: statistics, backups, drafts
  • Protecting a folder on static hosting with no other mechanism
  • Temporary access to material for a client or a contractor
  • Accounts for scripts, CI runners and monitoring
  • Compatibility with an old application that expects a finished password file

Where htpasswd setups go wrong

The most common mistake is copying a block from Apache 2.2 onto a 2.4 server and wondering why the protection does nothing, or worse, lets everybody in. Second place goes to a relative path in AuthUserFile, or a path relative to the site directory: Apache expects an absolute path from the root of the filesystem. Third is forgetting the permissions and dropping the file into a directory that is served over HTTP, where anybody can download the password file.

Next comes trying to guess a password from its {SHA} hash, which is hopeless because the function is one-way. Then there is generating a clear-text line and writing it into the file, which Apache will not accept. And the last one is forgetting HTTPS: with basic authentication the username and password travel in an Authorization header encoded in base64, so they are very nearly in the clear, and without an encrypted channel anybody on the way can read them. Sending the password over HTTPS is still the right thing to do, but at least it does not sit on the wire in plain sight.

  • Moving a block with Order and Deny onto an Apache 2.4 server
  • Giving a relative path in AuthUserFile
  • Putting the password file in a directory served over HTTP
  • Trying to crack a password when you know its SHA-1
  • Turning on basic authentication without HTTPS

Worked example: assembling a setup that actually works

Step one is the password. Type it into the field and you get a line like admin:{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=. That is base64 of the twenty bytes of the SHA-1 hash, and it is exactly how Apache expects to see the password in the file. The username in the line has to be the one you type when logging in, and it cannot contain a colon, otherwise the line splits in the wrong place.

Step two is the file on the server. Create it with the htpasswd -c command, paste the generated line into it, set permissions to 640 and give ownership to the web server. Step three is the .htaccess next to the protected directory: four directives, Require valid-user, and the path to the password file. Step four is the check: open the protected address, confirm the server asks for a login, and confirm the login works.

What happens at each step

StepActionResult
1Enter username and passwordit is checked that neither holds a colon or a space
2Compute the hashWeb Crypto returns 20 bytes of SHA-1 over the UTF-8 password
3Encode to base6420 bytes become 28 characters ending with «=»
4Assemble the lineusername, colon, the {SHA} prefix and the hash
5Write the filethe line goes into .htpasswd on the server
6Give the pathAuthUserFile receives an absolute path to the file
7Permissions640 on the file and 750 on the directory, owned by the web server
8Test the loginApache asks for the password and compares the hash

Steps two to four happen in the browser, the rest happen on the server, which is where Apache has to verify the password anyway.

Apache 2.2 and 2.4, Require and Order, HTTP and HTTPS

The main difference between the generations of Apache lies in the authorisation syntax. In 2.2 access was described as an ordered list of rules: Order allow,deny set the order in which they were evaluated, Allow from all or Deny from listed the addresses, and a Require closed the construct. In 2.4 only Require is left, and the rules all apply at once instead of one after another. The practical advice follows from that: on a 2.4 server use Require valid-user, and on a 2.2 server do not throw away Order and Deny until you have moved.

The second difference is the transport. Basic authentication sends the username and password in the Authorization header, encoded in base64, with no encryption whatsoever. Over HTTP that means the password is visible to anyone listening on the way. HTTPS here is not an improvement, it is a precondition: without it the protection only works against people who are not reading the network. The third difference concerns the file format: Apache 2.4 also works with password files produced by other programs, and there the only thing that matters is that the hash scheme is one the server knows how to verify.

  • Apache 2.4: Require valid-user instead of Order, Allow and Deny
  • Apache 2.2: the old syntax stays mandatory until the move happens
  • Basic authentication without HTTPS sends the password nearly in the clear
  • The password file format has to match what the server can verify
  • The saltless {SHA} scheme gives identical hashes for identical passwords

Common questions about htpasswd and Apache

Why is bcrypt computed on the server instead of in the browser?

Because bcrypt is deliberately slow. It runs thousands of rounds of a key derivation internally, and that slowness is exactly what makes brute forcing expensive: the more rounds, the longer a single check takes. In a browser that job freezes the interface for seconds and repeats work the server has to do anyway at login time. On top of that there is no bcrypt implementation in the browser without an external library, and pulling in a library for a single hash is not worth it. Hence the split: SHA-1 is computed in the browser through Web Crypto, and for bcrypt you get a command that is quick to run on the server.

What is Require valid-user, and why not Order and Deny?

Require valid-user is the Apache 2.4 authorisation directive: it means «let the user through if they are in the password file». The old Apache 2.2 syntax looked like Order allow,deny together with Allow from all and Deny from, and described access as an ordered list of rules. In version 2.4 those three directives were removed completely, and the new Require works differently: rules are no longer evaluated in sequence, they all apply at once. An old block moved over as is either stops working or starts letting everyone through. If the server is still on 2.2, the old syntax is still mandatory, but moving such sites to 2.4 is sensible regardless.

Why is bcrypt better than SHA-1 for passwords?

For three reasons. The first is salt: bcrypt generates one for every password and stores it inside the string, so two identical passwords produce different hashes and you cannot tell from the file who reuses a password. The {SHA} scheme has no salt at all. The second is speed: SHA-1 runs billions of times per second on a graphics card, bcrypt with the default settings runs hundreds of times per second on a processor, and the gap is wide enough to make brute forcing impractical. The third is tunable cost: you can raise it as hardware gets faster. For more on the subject, see the piece on strong passwords and the difference between MD5 and SHA-256 hashes.

How do I recover a password stored as SHA-1 in .htpasswd?

You cannot, and with bcrypt there is a reason why. In the {SHA} scheme the check is simple: compute SHA-1 of the typed password, compare it with the stored value in base64, and if they match the password was right. That does not work with bcrypt, because the string carries the salt, the cost and the result of a thousand rounds, while the password itself is stored nowhere. The only way to find it is to run through a dictionary of candidates and compare each result with the saved hash. That is why a lost password is not something you remember but something you reset: replace the line in the file with a new one.

Where should .htpasswd live, and what permissions should it have?

The file usually sits next to the protected directory or higher up the tree, and the name is chosen so that it cannot be guessed: .htpasswd is the usual name, but htpasswd.bak turns up too. Permissions matter more than the name. A file with passwords must not be readable by unrelated accounts, so the directory is closed to 750 and the file itself to 640, owned by the user the web server runs as. If you place the file in the site root where HTTP access is possible, the name has to begin with a dot.

Can I store the password in clear text?

Apache will not do it: a line with a bare password does not count as a password, and authentication fails. But if you write such a line by hand, the password leaks with the first backup, the first time the file lands in a repository, and any time somebody lists the directory. The -p option in htpasswd exists only on Windows and for testing, and it has no place in a production password file. If you genuinely need that format, for example to compare against another system, the line is handed over with a clear warning that it is plain text and not a hash.

Why does Apache answer with a 500 error when I try to log in?

Most often because AuthName is missing or the path in AuthUserFile is wrong. Apache wants the complete set: AuthType Basic, AuthName with a realm name, AuthUserFile with an absolute path, and Require valid-user. Without AuthName the server refuses to set up the protection and fails with an internal error. A frequent second cause is the path: it is given from the root of the filesystem, not from the site directory, and relative paths are not accepted. A third cause is the file being unreadable by the web server account: permissions of 640 owned by somebody else produce the same 500.

How do I change the password of an existing user?

You can edit the .htpasswd file in a text editor: it is ordinary text, and the new line simply replaces the old one. Or you can do it on the server: the htpasswd command with the path to the file and the username asks for a new password and rewrites that one line, leaving the others alone. With many users, changing them one by one is tedious and it is easier to regenerate the file with -c and hand out a separate line to each person. One important detail: do not delete the old file until the new one is in place and a login has been tested.

Related tools