I have wanted to explore the use of WordPress as a back end for Single Page Applications for some time. I installed the WordPress REST API v2 and have tried various types of authentication. I’m not a big fan of OAuth so I originally tried Basic Authentication just to get things working. GETting page information worked just fine with or without authentication because GET requests generally don’t require auth. However, POST or PUT requests would fail with a 401.

I thought maybe it was because the Basic Authentication plugin was pretty old and not well tested with the latest version of WordPress. So, I also tried using Application Passwords, which is cooler and safer anyway. Unfortunately, I only got 401s with that too.

After much Googling with few results, and having minimal time to pursue information, I gave up and moved on. Recently, however, I’ve had renewed interest in being able to interact with WordPress via an Angular2 app. I dusted off my test blog with the WordPress API installed and started poking at it again. I crawled through the REST API plugin code to try to figure out why authentication was failing and found the “rest_cannot_edit” message in the class-wp-rest-posts-controller.php file. After tracing the path of authentication through WordPress core and plugins, I became suspicious that authentication was not even being attempted. I serialized the $request object available to the permissions check methods and returned it with the 401 response. Sure enough, no authorization header was present in the request object!

I took my inspection higher and realized that the Authorization header was being stripped at the server level, before WordPress or even PHP could use the information. I’m aware that some shared hosts do this but I was testing this on a VPS. I did not expect my VPS provider to have that set up by default. I found some .htaccess rules that would work around this but they didn’t seem to work (my .htaccess skills are rusty at best).

After going down a couple of rabbit holes related to server settings and PHP configurization I contacted my server support team via live chat. While waiting for them to respond I took another look at the .htaccess file and moved some stuff around on a whim. To my surprise, my next Postman request returned a post object with an updated title!

So after all of my work and suspicions that plugins were outdated, my password was wrong and a hundred other false leads… it turned out to just be an annoying server config that was not mentioned on any wiki I could find on my provider site.

So, if you have 401 Not Authorized response on all WordPress Rest API requests, you’ve checked your username, password, base64 encoding and header formatting…it’s probably your hosting provider and it may be possible to allow the HTTP Auth via your .htaccess file. WordPress’ .htaccess file looks like this out of the box:

# 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

Update it to look like this:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

# Enable HTTP Auth
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1]

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

</IfModule>

# END WordPress

The [L] at the end of those lines means “last” so the server will stop processing the file after the wordpress conditions are met, before the auth rule is applied. So, the auth rules need to come before the WordPress default rules or they will never be applied!

Hopefully this helps the next person, I wasted a lot of time on this.

Categories: Software

1 Comment

robyn · April 24, 2020 at 6:16 pm

Thank you SO incredibly much for this. You have no idea how much time my team and I spent going in circles on this. Your article was the solution. Thank you very much!

Leave a Reply

Your email address will not be published. Required fields are marked *