There are questions all over the internet regarding how to password protect a sub-directory when you are using WordPress.
I just spent a long time fighting a frustrating battle with this as well. So I’m documenting the resolution here for my (and anyone’s) benefit.
In short
- WordPress does not mess with requests to actual directories or files.
- If WordPress is messing with your request then you aren’t requesting an actual directory or file.
- It’s likely your Error codes aren’t setup to return actual files.
- Make sure your .htaccess file isn’t generating 500 errors (i.e. ensure the path to your .htpasswd file is correct).
Problem
I’ve added a .htaccess and .htpasswd file but all I see is a WordPress 404 page. I can’t stop crying because it’s not working and my brain hurts.
Yep. That happens. WordPress comes with the following .htaccess file by default:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Let’s break this down. First we are checking if the mod_rewrite module is even installed. If it is then we are turning the RewriteEngine on. That’s all great. We wouldn’t want to use the engine if it didn’t exist… right?
RewriteBase /
– This sets the base of every subsequent Rule and Condition to the root `/`. This way we don’t have to include the root directory at the beginning of any of our rules.
RewriteRule ^index\.php$ - [L]
– This rewrite rule checks to see if we are on the index.php page already. The dash in the rule means do nothing. So… if we are already on index.php don’t do anything. The [L]
option means that we should stop processing rules now. Don’t do anything else, we’ve got what we wanted. Quite literally this is the [L]ast rule that should be processed.
RewriteCond %{REQUEST_FILENAME} !-f
– This condition makes sure that if the current request is hitting an actual existing file then we should do nothing. So WordPress won’t mess with your requests if you try to link to an actual file.
RewriteCond %{REQUEST_FILENAME} !-d
– This condition makes sure that if the current request is hitting an actual existing directory that we should do nothing. So WordPress won’t mess with your requests if you try to link to an actual directory.
RewriteRule . /index.php [L]
– Finally, if our request passed the above two conditions (it’s not an actual file and not an actual directory) then map the request to index.php. Now the request is mapped and WordPress can do its thing!
That’s Great But…
I know what you are thinking. You are thinking:
If what you are saying is true, then I shouldn’t be seeing a 404 page. My password protected directory actually exists!
Yes. You are correct, your directory does exist.
Solution
When you password protect a directory with .htaccess you are telling the server to return a certain response code. The 401 response code meaning the user is unauthorized, to be precise. When the browser received this response code it triggers a username and password prompt. However, and here is the problem, the browser is never receiving the response code.
Why is the browser not receiving the response code?
Good question. If you remember the WordPress .htaccess checks if the requested url points an actual file or directory. It only rewrites you to the index.php file if you aren’t actually requesting a file or directory. When you throw the 401 response code you aren’t actually requesting a file or directory. You are essentially requesting nothing (because you are unauthorized). So the WordPress .htaccess file is behaving correctly – it’s rewriting you to the index.php page and giving you a 404 (because more than likely your password protected directory does not match a permalink on your WordPress blog).
So… if WordPress is making sure that you actually requested a file then… you need to make sure that you are actually getting a file! You can do this by adding the following line to the top of your WordPress .htaccess file:
ErrorDocument 401 default
What you are doing is telling the server to return the default 401 file when it encounters a 401 response code. Once you are returning an actual file WordPress won’t try to grab your request.
Ok. I added that and I’m still having issues. What gives?
If you are like me, then the 401 response code fix wasn’t enough. You are still having the same issue and by now you are wanting to… oh gosh I can’t even think of anything to describe this type of pain.
Let’s look at our .htaccess file we are using to password protect our sub-directory. If you are anything like me your file might’ve looked something like this.
AuthType Basic
AuthName "Password Protected Area"
AuthUserFile /public_html/jeremysawesome.com/mySecretDirectory/.htpasswd
Require valid-user
This looks perfectly valid to me. However, it turns out this file is generating Internal Server Errors! (I know because I added a ErrorDocument 500 default
line to my WordPress .htaccess file just for kicks.) But this shouldn’t be generating a 500 error unless I’m doing something wrong.
Turns out. I was.
The AuthUserFile
argument needs to be the full server path to your .htpasswd file. Turns out, /public_html
wasn’t actually the beginning of my server path. As a result the server was throwing a 500 error. Once I figured out what my entire full server path was, and added that to my .htaccess file, everything started working.
To Recap
- WordPress does not mess with requests to actual directories or files.
- If WordPress is messing with your request then you aren’t requesting an actual directory or file.
- It’s likely your Error codes aren’t setup to return actual files.
- Make sure your .htaccess file isn’t generating 500 errors (i.e. ensure the path to your .htpasswd file is correct).
Whew! Thank goodness that’s over. Happy Blogging 🙂