Authenticating a node.js app with WP-API

We’re currently working on a React.js app that uses WordPress as a data store. The WP-API plugin (which will be integrated into core at some point) is fantastic. It allows us to use all the content creation goodness of WordPress behind the scenes and build whatever (however) we want for the front end – we’re no longer restricted to building traditional WordPress themes.

Using the WP-OAuth plugin (spoiler: we can’t)

The plugin only allows cookie-based authentication out of the box. This is fine if you’re building a React component into an existing theme (where your user will have appropriate cookies), but it won’t work if you’re building a mobile or desktop app to consume WordPress data. For this, we have to use the WP-OAuth plugin to enable OAuth 1.0a. It’s a shame that they haven’t built an OAuth 2.0 plugin for the API yet (as that looks much easier to implement), but for the moment we’re stuck with old three-legged 1.0a.

Rolling our own

Let’s get stuck in. Thanks to Bruno Skvorc at Sitepoint for the inspiration, as well as santosh79 and mccahill on Github for the practicalities of getting Twitter authentication working with older versions of Express. “Twitter authentication” you say? Well, it turns out that OAuth 1.0a is quite similar across implementations.

We’ll assume you have some familiarity with node.js, your terminal, and of course, WordPress. You’ll also have to get WP-API and WP-OAuth installed. We’re giving Mac-specific instructions here, particularly around port forwarding, but they should be easy enough to adapt for Linux.

Using a localhost callback URL

By default, WP-OAuth uses wp_http_validate_url() to prevent localhost URLs from being used as a callback. I’m not sure why this is (and please feel free to tell me in the comments if you know), but inthis context, it would prevent us from testing our code in our local development environment.

To get around this, I’ve written a very small plugin to remove this restriction. Feel free to inspect the code – all three lines!

Port forwarding

Sadly that plugin doesn’t solve all of our invalid callback problems. WordPress also balks at forwarding to URLs that have a port number specified. If you run your node server on port 80, this shouldn’t be a problem; however, most of us have an Apache server running on port 80. In our case, we’re serving our Node app on port 9090, so we need to set up a little spoof to redirect WordPress.

First, set up an entry in your hosts file to redirect calls to wp-oauth-test.local to You can do this directly in your hosts file, or on Mac we use Gas Mask.

Second, set up a port forward for requests received on back to (the actual host and port of our Node server). If you get lost with port forwarding, check out Sal Ferrarello’s guide to port forwarding.

$ echo "rdr pass inet proto tcp from any to port 80 -> port 9090" | sudo pfctl -ef -

Get the code

I’ve split the Node app up into two files: a config file along with the main app. Pull the repo:

$ git clone

Install Node dependencies

$ npm install

I’ve included a sample config file (where the actual config file is ignored by the .gitignore). Make a copy.

$ mv config-sample.js config.js

Edit the config file. Change HOSTPATH to match the URL that you set up in your host file earlier. Change WP_INDEX_ENDPOINT to match the index URL of WordPress’s API.

module.exports = {
'HOSTPATH': 'http://wp-oauth-test.local',
'PORT': 9090,
'EXPRESS_SESSION_SECRET': 'imareallysecretkeythatyoucouldntpossiblyguess',
'WP_CONSUMER_KEY': '3g375RyVuPDp',
'WP_CONSUMER_SECRET': 'UhDZ7864x6n8V2HgIwnhoaFKN2xr7GihxfYYS6H0kzeZPrRQ',

Start the server…!

$ NODE_ENV=development node wp-oauth-test.js

With any luck, your server should start. You may find that there are some notices about some express-session options being deprecated. After a short delay, you’ll see the request/response/authorise URLs for your WordPress install echoed to the terminal. Once you’ve got that, you’re ready to go. Go to the URL that you specified in your hosts file.


Screen Shot 2015-10-16 at 16.58.53

This is by no means perfect, but it’s a start. If you have any comments or suggestions for improvement, either comment below or submit a pull request on GitHub.